#ifndef MFILER2_DIRWND
#define MFILER2_DIRWND

extern "C"
{
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
}

/// ファイル情報 ///
struct sFile{
    char mName[PATH_MAX];           // ディスク内部の名前
    char mNameView[PATH_MAX];       // 表示する時の名前(iconvで変換後)
    char mLinkTo[PATH_MAX];         // リンク先
    struct stat mStat;              // stat()のキャッシュ
    struct stat mLStat;             // lstat()のキャッシュ
    bool mMark;                     // マークされているかどうか
    char mUser[256];                // ユーザー名
    char mGroup[256];               // グループ名

    char mView[256];                // 描写用のバッファ
    int mViewAttr;                  // 描写用のバッファ

    int mSortRandom;                // ランダムソート時の数値

    sFile(char* name, char* name_view, char* linkto, struct stat* stat_, struct stat* lstat_, bool mark, char* user, char* group, int uid, int gid)
    {
        strcpy(mName, name);
        strcpy(mNameView, name_view);
        strcpy(mLinkTo, linkto);
        mStat = *stat_;
        mLStat = *lstat_;
        mMark = mark;
        if(user == NULL) {
            sprintf(mUser, "%d", uid);
        }
        else {
            strcpy(mUser, user);
        }
        if(group == NULL) {
            sprintf(mGroup, "%d", gid);
        }
        else {
            strcpy(mGroup, group);
        }

        mSortRandom = 0;
    }
};

/// ディレクトリ情報 ///
struct sDirInfo {
    char mPath[512];
    int mScrollTop;
    int mCursor;
};

class cDirWnd {
    char mPath[PATH_MAX];               // 現在のパス 最後の文字は'/'
    char mPathBefore[PATH_MAX];         // 一つ前のパス
    hash_obj* mMarkFiles;               // マークファイル
    hash_obj* mFileNum;
    list_obj* mFileNum2;

    vector_obj* mFiles;
    
    int mScrollTop;
    int mCursor;

    char mMask[1024];
    
    list_obj* mDirStack;
   
    static BOOL sort_name(void* left, void* right);
    static BOOL sort_name_reverse(void* left, void* right);
    static BOOL sort_ext(void* left, void* right);
    static BOOL sort_ext_reverse(void* left, void* right);
    static BOOL sort_size(void* left, void* right);
    static BOOL sort_size_reverse(void* left, void* right);
    static BOOL sort_time(void* left, void* right);
    static BOOL sort_time_reverse(void* left, void* right);
    static BOOL sort_user(void* left, void* right);
    static BOOL sort_user_reverse(void* left, void* right);
    static BOOL sort_group(void* left, void* right);
    static BOOL sort_group_reverse(void* left, void* right);
    static BOOL sort_permission(void* left, void* right);
    static BOOL sort_permission_reverse(void* left, void* right);
    static BOOL sort_random(void* left, void* right);

    static const int kMaxYMinus = 4;

    void read();
    bool check_path(char* new_path);
    void clear_dir_stack();
    void hash_file_num_reset();
    void make_file_stat(sFile* file, char* buf);
    void make_file_name(sFile* file, char* fname, char** ext, char* dot, int name_len);
public:
    cDirWnd(char* path, bool active);
    ~cDirWnd();

    static void Init();
    static void Final();

    static void* operator new(size_t size) { return MALLOC(size); }
    static void operator delete(void* p) { FREE(p); }

    static const int kDirStackSize = 500;
    static bool gRemainMarks;

    /// properties ///
    bool mActive;
   
    enum eSortKind { kName, kNameReverse, kExt, kExtReverse, kSize, kSizeReverse, kTime, kTimeReverse, kUser, kUserReverse, kGroup, kGroupReverse, kPermission, kPermissionReverse, kRandom, kNone, kSortMax };
    eSortKind mSortKind;

    static char* kSortName[cDirWnd::kSortMax];

    enum eViewOption { kAll, kOneDir, kOneDir2, kOneDir3, kOneDir5 };
    static eViewOption gViewOption;
    bool mViewNameOnly;

    static bool gViewMTime;
    static bool gViewSize;
    static bool gViewGroup;
    static bool gViewOwner;
    static bool gViewNLink;
    static bool gViewPermission;
    static bool gViewFnameDivideExt;

    bool mViewFocusBack;
    bool mViewRemoveDir;
    
    vector_obj* Files() { return mFiles; }
    sFile* CursorFile();

    struct stat* CursorFileLStat() {
        return &((sFile*)vector_item(mFiles, mCursor))->mLStat;
    }


    sFile* File(int num);
    char* Path() { return mPath; }
    VALUE MarkFiles();
    VALUE MarkFilesFullPath();
    VALUE MarkFilesConvert();
    VALUE MarkFilesFullPathConvert();
    ALLOCATED string_obj* MarkFilesNoSQuote();
    ALLOCATED string_obj* MarkFilesNoSQuoteFullPath();
    ALLOCATED string_obj* MarkFilesSQuote();
    ALLOCATED string_obj* MarkFilesSQuoteFullPath();
    int MarkFileNum();
    double MarkFileSize();
    int FileNum(char* fname);

    bool Marking();                                // 現在マーク中か？
    bool IsSameExtensionMarked(char* result);      // 拡張子同一のファイルをマーク中か？
    bool IsDirectoryMarked();                      // ディレクトリをマーク中か？
    bool IsExecutiveFileMarked();                  // 実行ファイルをマーク中か？
    bool IsLinkMarked();                           // リンクをマーク中か？

    bool IsLeftDir();
    bool IsRightDir();

    /// methods ///
    int Cursor();
    int CursorMax();
    int CursorX();
    int CursorY();
    int CursorMaxX();
    int CursorMaxY();
    void MoveCursor(int index);
    int ScrollTop();
    void SetScrollTop(int index);
    
    void Mark();
    void Mark2(int index);      // 反転
    void Mark3(int index);      // マークする
    void MarkAll();
    void MarkAllFiles();
    void MarkOff(int index);
    void MarkOff(char* fname);
    void ResetMarks();
    
    void Activate(cDirWnd* current);
   
    bool Move(char* path);        // last char don't have to be '/'
    void MoveBack();

    void SelectTab();
    void PushDir(int num, char* path, int scroll_top, int cursor);
    void PushBackTab();
    static void CloseTab(int num);
    void UpTab(int num);
    static int TabMax();
    static void TabNew(int num, char* path, int scroll_top, int cursor);
    static char* TabPath(int num);
    static int TabScrollTop(int num);
    static int TabCursor(int num);
    static VALUE TabOutOfFind(int num);
   
    void Sort();
    void View();
    void ChangeSort();

    void MakeSizeStr2(char* result, double size);
    void SelectDirView();
    void SelectDirInput(int meta, int key);

    void DeleteFileFromFileList(int num);

    void Reread();
    bool ChangeMask(char* mask);
    char* Mask() { return mMask; }
    
    void AddFile(char* fname);      // ディスク上にあってstatできる場合
    void AddFile2(char* fname, char* linkto, int kind, bool user_r, bool user_w, bool user_x, bool group_r, bool group_w, bool group_x, bool other_r, bool other_w, bool other_x, int size, time_t mtime, char* user, char* group);
        // kind 0: レギュラーファイル 1: ディレクトリ 2: リンク
};

extern cDirWnd* ActiveDir();
extern cDirWnd* SleepDir();
extern bool gSelectDir;
extern vector_obj* gDirStack;                   // ディレクトリスタック sDirInfoの配列
extern int gDirScrollTop;                   // ディレクトリスタック選択画面のスクロール位置
extern int gDirCursor;                      // ディレクトリスタック選択画面のカーソル位置
extern int gViewHookLineNum;                // ファイラ画面のフックの描写行数

extern VALUE gOptionPageViewWay;          // 現在のページ数パーセント表示するか

enum eFileSizeViewWay { kFSHuman = 0, kFSNormal, kFSPlane };
extern VALUE gFileSizeViewWay;              // ファイルのサイズ表示をどうするか

extern VALUE gSortMarkFileUp;                       // マークしたファイルを上に上げるかどうか
extern VALUE gSortDirUp;                    // ソート時ディレクトリを上に上げるかどうか

int convert_fname(char* src, char* des, int des_size); // file mei convert

#endif
