#include "common.h"

extern "C"
{
#include <dirent.h>
#include <libgen.h>
#include <termios.h>
#include <time.h>
#include <sys/ioctl.h>
}

bool cDirWnd::gRemainMarks = true;

char* cDirWnd::kSortName[cDirWnd::kSortMax] = {
    "name", "name_rev", "extension", "extension_rev", "size", "size_rev",
    "time", "time_rev", "user", "user_rev", "group", "group_rev"
};

static vector_obj* gDirStack;
static int gDirScrollTop = 0;
static int gDirCursor = 0;
bool gSelectDir = false;

void cDirWnd::Init()
{
    gDirStack = vector_new(10);
}

void cDirWnd::ReadHistory()
{
    char* home = getenv("HOME");
    if(home == NULL) {
        return;
    }

    char path[PATH_MAX];
    sprintf(path, "%s/.mfinfo", home);
    FILE* f = fopen(path, "r");
    if(f == NULL) return;
    
    int value;
    fscanf(f, "%d", &value);
    switch(value) {
        case 0:
            cDirWnd::gSortKind = kName;
            break;
        case 1:
            cDirWnd::gSortKind = kNameReverse;
            break;
        case 2:
            cDirWnd::gSortKind = kExt;
            break;
        case 3:
            cDirWnd::gSortKind = kExtReverse; 
            break;
        case 4:
            cDirWnd::gSortKind = kSize;
            break;
        case 5:
            cDirWnd::gSortKind = kSizeReverse;
            break;
        case 6:
            cDirWnd::gSortKind = kTime;
            break;
        case 7:
            cDirWnd::gSortKind = kTimeReverse;
            break;
        case 8:
            cDirWnd::gSortKind = kUser;
            break;
        case 9:
            cDirWnd::gSortKind = kUserReverse;
            break;
        case 10:
            cDirWnd::gSortKind = kGroup;
            break;
        case 11:
            cDirWnd::gSortKind = kGroupReverse;
            break;
    }

    fscanf(f, "%d", &value);
    switch(value) {
        case 0:
            cDirWnd::gViewOption = kAll;
            break;
        case 1:
            cDirWnd::gViewOption = kOneDir;
            break;
        case 2:
            cDirWnd::gViewOption = kOneDir2;
            break;
        case 3:
            cDirWnd::gViewOption = kOneDir3;
            break;
        case 4:
            cDirWnd::gViewOption = kOneDir5;
            break;
    }

    fscanf(f, "%d", &value);
    if(value == 0) {
        cDirWnd::gSortDirUp = true;
    }
    else {
        cDirWnd::gSortDirUp = false;
    }

    fscanf(f, "%d", &value);
    if(value == 0) {
        cDirWnd::gViewNameOnly = true;
    }
    else {
        cDirWnd::gViewNameOnly = false;
    }

    fscanf(f, "%d", &value);
    if(value == 0) {
        gColor = true;
    }
    else {
        gColor = false;
    }

    char buf[1024];
    fscanf(f, "%s", buf);
    gLDir->ChangeMask(buf);
    
    fscanf(f, "%s", buf);
    gRDir->ChangeMask(buf);

    int scroll_top;
    int cursor;
    if(fscanf(f, "%s %d %d", path, &scroll_top, &cursor) == 3) {
        gLDir->Move(path);
        gLDir->SetScrollTop(scroll_top);
        gLDir->MoveCursor(cursor);
    }
    if(fscanf(f, "%s %d %d", path, &scroll_top, &cursor) == 3) {
        gRDir->Move(path);
        gRDir->SetScrollTop(scroll_top);
        gRDir->MoveCursor(cursor);
    }

    while(1) {
        if(fscanf(f, "%s %d %d", path, &scroll_top, &cursor) == 3) {
            sDirInfo* dinfo = (sDirInfo*)MALLOC(sizeof(sDirInfo));

            strcpy(dinfo->mPath, path);
            dinfo->mScrollTop = scroll_top;
            dinfo->mCursor = cursor;

            vector_add(gDirStack, dinfo);
        }
        else
            break;
    }


    fclose(f);
}

void cDirWnd::SaveHistory()
{
    /// save path ///
    char* home = getenv("HOME");
    if(home == NULL) {
        return;
    }

    char path[PATH_MAX];
    sprintf(path, "%s/.mfinfo", home);
    
    FILE* f = fopen(path, "w+");

    switch(cDirWnd::gSortKind) {
        case kName:
            fprintf(f, "0\n");
            break;
        case kNameReverse:
            fprintf(f, "1\n");
            break;
        case kExt:
            fprintf(f, "2\n");
            break;
        case kExtReverse:
            fprintf(f, "3\n");
            break;
        case kSize:
            fprintf(f, "4\n");
            break;
        case kSizeReverse:
            fprintf(f, "5\n");
            break;
        case kTime:
            fprintf(f, "6\n");
            break;
        case kTimeReverse:
            fprintf(f, "7\n");
            break;
        case kUser:
            fprintf(f, "8\n");
            break;
        case kUserReverse:
            fprintf(f, "9\n");
            break;
        case kGroup:
            fprintf(f, "10\n");
            break;
        case kGroupReverse:
            fprintf(f, "11\n");
            break;
    }

    switch(cDirWnd::gViewOption) {
        case kAll:
            fprintf(f, "0\n");
            break;
        case kOneDir:
            fprintf(f, "1\n");
            break;
        case kOneDir2:
            fprintf(f, "2\n");
            break;
        case kOneDir3:
            fprintf(f, "3\n");
            break;
        case kOneDir5:
            fprintf(f, "4\n");
            break;
    }

    if(cDirWnd::gSortDirUp) {
        fprintf(f, "0\n");
    }
    else {
        fprintf(f, "1\n");
    }

    if(cDirWnd::gViewNameOnly) {
        fprintf(f, "0\n");
    }
    else {
        fprintf(f, "1\n");
    }

    if(gColor) {
        fprintf(f, "0\n");
    }
    else {
        fprintf(f, "1\n");
    }

    fprintf(f, "%s %s\n", gLDir->mMask, gRDir->mMask);

    fprintf(f, "%s %d %d\n", gLDir->mPath, gLDir->mScrollTop, gLDir->mCursor);
    fprintf(f, "%s %d %d\n", gRDir->mPath, gRDir->mScrollTop, gRDir->mCursor);

    const int len = vector_size(gDirStack);
    for(int i=0; i<len; i++) {
        sDirInfo* item = (sDirInfo*)vector_item(gDirStack, i);
        
        fprintf(f, "%s %d %d ", item->mPath, item->mScrollTop
                        , item->mCursor);    
    }

    fclose(f);
}

void cDirWnd::Final()
{
    SaveHistory();

    for(int i=0; i<vector_size(gDirStack); i++) {
        FREE(vector_item(gDirStack, i));
    }
    vector_delete(gDirStack);
}

void cDirWnd::PushDir(int num, char* path, int scroll_top, int cursor)
{
    sDirInfo* dinfo = (sDirInfo*)MALLOC(sizeof(sDirInfo));

    strcpy(dinfo->mPath, path);
    dinfo->mScrollTop = scroll_top;
    dinfo->mCursor = cursor;

    vector_insert(gDirStack, num, dinfo);
}

void cDirWnd::PushFrontDir()
{
    sDirInfo* dinfo = (sDirInfo*)MALLOC(sizeof(sDirInfo));

    strcpy(dinfo->mPath, mPath);
    dinfo->mScrollTop = mScrollTop;
    dinfo->mCursor = mCursor;

    vector_insert(gDirStack, 0, dinfo);
}

void cDirWnd::PushBackDir()
{
    sDirInfo* dinfo = (sDirInfo*)MALLOC(sizeof(sDirInfo));

    strcpy(dinfo->mPath, mPath);
    dinfo->mScrollTop = mScrollTop;
    dinfo->mCursor = mCursor;

    vector_add(gDirStack, dinfo);
}

void cDirWnd::PopDir()
{
    if(vector_size(gDirStack) > 0) {
        sDirInfo* dinfo = (sDirInfo*)vector_pop_front(gDirStack);
        
        Move((char*)dinfo->mPath);
        SetScrollTop(dinfo->mScrollTop);
        MoveCursor(dinfo->mCursor);
        
        FREE(dinfo);
    }
}

void cDirWnd::CloseTab(int num)
{
    if(num >=0 && num < vector_size(gDirStack)) {
        void* item = vector_erase(gDirStack, num);
        FREE(item);
    }
}

void cDirWnd::UpTab(int num)
{
    if(num >=0 && num < vector_size(gDirStack)) {
        PushDir(num, mPath, mScrollTop, mCursor);

        sDirInfo* dinfo = (sDirInfo*)vector_item(gDirStack, num+1);

        Move((char*)dinfo->mPath);
        SetScrollTop(dinfo->mScrollTop);
        MoveCursor(dinfo->mCursor);

        FREE(dinfo);
        vector_erase(gDirStack, num+1);
    }
}

int cDirWnd::TabMax()
{
    return vector_size(gDirStack);
}

void cDirWnd::TabNew(char* path)
{
    if(path[strlen(path)-1] != '/') {
        strcat(path, "/");
    }

    sDirInfo* dinfo = (sDirInfo*)MALLOC(sizeof(sDirInfo));
    strcpy(dinfo->mPath, path);
    dinfo->mScrollTop = 0;
    dinfo->mCursor = 0;

    vector_add(gDirStack, dinfo);
}

char* cDirWnd::TabPath(int num)
{
    if(num >=0 && num < vector_size(gDirStack)) {
        sDirInfo* dinfo = (sDirInfo*)vector_item(gDirStack, num);

        return dinfo->mPath;
    }

    return NULL;
}

void cDirWnd::SelectDir()
{
    if(vector_size(gDirStack) == 1) {
        PushFrontDir();
        
        sDirInfo* dinfo = (sDirInfo*)vector_item(gDirStack, 1);
        
        Move((char*)dinfo->mPath);
        SetScrollTop(dinfo->mScrollTop);
        MoveCursor(dinfo->mCursor);
        
        FREE(dinfo);
        vector_erase(gDirStack, 1);
    }
    else if(vector_size(gDirStack) > 1) {
        gDirScrollTop = 0;
        gDirCursor = 0;
        gSelectDir = true;
    }
}

cDirWnd* ActiveDir()
{
    if(gLDir->mActive)
        return gLDir;
    else
        return gRDir;
}

cDirWnd* SleepDir()
{
    if(!gLDir->mActive)
        return gLDir;
    else
        return gRDir;
}

bool cDirWnd::gSortDirUp = true;
cDirWnd::eSortKind cDirWnd::gSortKind = cDirWnd::kName;
cDirWnd::eViewOption cDirWnd::gViewOption = cDirWnd::kAll;
bool cDirWnd::gViewNameOnly = false;

cDirWnd::cDirWnd(char* path, bool active)
{
TBEGIN();

    char path1[PATH_MAX];

    if(path == NULL) {
        char* cwd = mygetcwd();
        
        char tmp[PATH_MAX];
        strcpy(tmp, cwd);
        if(strcmp(tmp, "/") != 0) strcat(tmp,"/");

        strcpy(path1, tmp);

        FREE(cwd);
    }
    else {
        strcpy(path1, path);
    }

    mFiles = vector_new(30);
    mDirStack = list_new();
    mMarkFiles = hash_new(30);

    char path3[PATH_MAX];
    if(!correct_path(path1, path3)) {
        strcpy(path3, "/");
    }

    if(path3[strlen(path3)-1] != '/') {
        strcat(path3, "/");
    }
    
    strcpy(mPath, path3);
    strcpy(mMask, "{*,.*}");
    strcpy(mPathBefore, "");

    read();

    mActive = active;
    mScrollTop = 0; 
    if(vector_size(mFiles) <= 2)
        mCursor = 1;
    else
        mCursor = 2;
        
    Sort();

TEND();
}

cDirWnd::~cDirWnd()
{
    hash_delete(mMarkFiles);
    for(list_it* i=list_begin(mDirStack); i; i=list_next(i)) {
        FREE(list_item(i));
    }
    list_delete(mDirStack);
    for(int i=0; i<vector_size(mFiles); i++) {
        delete (sFile*)vector_item(mFiles, i);
    }
    vector_delete(mFiles);
}

BOOL cDirWnd::sort_name(void* left, void* right)
{
    sFile* l = (sFile*) left;
    sFile* r = (sFile*) right;

    if(strcmp(l->mName, ".") == 0) return TRUE;
    if(strcmp(l->mName, "..") == 0) {
        if(strcmp(r->mName, ".") == 0) return FALSE;

        return TRUE;          
    }
    if(strcmp(r->mName, ".") == 0) return FALSE;
    if(strcmp(r->mName, "..") == 0) return FALSE;

    if(gSortDirUp) {
        if(!S_ISDIR(l->mStat.st_mode) && !S_ISDIR(r->mStat.st_mode)
            || S_ISDIR(l->mStat.st_mode) && S_ISDIR(r->mStat.st_mode) )
            {
            return strcmp(l->mName, r->mName) < 0;
            }

    
        if(S_ISDIR(l->mStat.st_mode)) return TRUE;
        return FALSE;
    }
    else {
        return strcmp(l->mName, r->mName) < 0;
    }
}

BOOL cDirWnd::sort_name_reverse(void* left, void* right)
{
    sFile* l = (sFile*) left;
    sFile* r = (sFile*) right;

    if(strcmp(l->mName, ".") == 0) return TRUE;
    if(strcmp(l->mName, "..") == 0) {
        if(strcmp(r->mName, ".") == 0) return FALSE;

        return TRUE;          
    }
    if(strcmp(r->mName, ".") == 0) return FALSE;
    if(strcmp(r->mName, "..") == 0) return FALSE;

    if(gSortDirUp) {
        if(!S_ISDIR(l->mStat.st_mode) && !S_ISDIR(r->mStat.st_mode)
            || S_ISDIR(l->mStat.st_mode) && S_ISDIR(r->mStat.st_mode) )
            {
            return strcmp(r->mName, l->mName) < 0;
            }

    
        if(S_ISDIR(r->mStat.st_mode)) return TRUE;
        return FALSE;
    }
    else {
        return strcmp(r->mName, l->mName) < 0;
    }
}
    
BOOL cDirWnd::sort_ext(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     char* lext = extname(l->mName);
     char* rext = extname(r->mName);
    
     bool result;
     if(gSortDirUp) {
         if(S_ISDIR(l->mStat.st_mode)) {
              if(S_ISDIR(r->mStat.st_mode))
                    result= strcmp(l->mName, r->mName) <0;
              else
                    result = TRUE;
         }
         else if(S_ISDIR(r->mStat.st_mode)) {
              result = FALSE;
         }
         else {
              const int cmp = strcmp(lext, rext);
              if(cmp == 0) {
                  result = strcmp(l->mName, r->mName) < 0;
              }
              else {
                  result = cmp < 0;
              }
         }
     }
     else {
         const int cmp = strcmp(lext, rext);
         if(cmp == 0) {
             result = strcmp(l->mName, r->mName) < 0;
         }
         else {
             result = cmp < 0;
         }
     }
    
     FREE(lext);
     FREE(rext);
    
     return result;
}
    
BOOL cDirWnd::sort_ext_reverse(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     char* lext = extname(l->mName);
     char* rext = extname(r->mName);
    
     bool result;
     if(gSortDirUp) {
         if(S_ISDIR(r->mStat.st_mode)) {
              if(S_ISDIR(l->mStat.st_mode))
                    result= strcmp(r->mName, l->mName) <0;
              else
                    result = TRUE;
         }
         else if(S_ISDIR(l->mStat.st_mode)) {
              result = FALSE;
         }
         else {
              const int cmp = strcmp(rext, lext);
              if(cmp == 0) {
                  result = strcmp(r->mName, l->mName) < 0;
              }
              else {
                  result = cmp < 0;
              }
         }
     }
     else {
         const int cmp = strcmp(rext, lext);
         if(cmp == 0) {
             result = strcmp(r->mName, l->mName) < 0;
         }
         else {
             result = cmp < 0;
         }
     }
    
     FREE(lext);
     FREE(rext);
    
     return result;
}
  
BOOL cDirWnd::sort_size(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;
     
     const int lsize = S_ISDIR(l->mStat.st_mode) ? 0 : l->mStat.st_size; 
     const int rsize = S_ISDIR(r->mStat.st_mode) ? 0 : r->mStat.st_size;

     if(lsize == rsize) {
         return strcmp(l->mName, r->mName) < 0;
     }
     else {
         return lsize < rsize;
     }
}
  
BOOL cDirWnd::sort_size_reverse(void* left, void* right)
{
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;          
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;
     
     const int lsize = S_ISDIR(l->mStat.st_mode) ? 0 : l->mStat.st_size; 
     const int rsize = S_ISDIR(r->mStat.st_mode) ? 0 : r->mStat.st_size;

     if(lsize == rsize) {
         return strcmp(r->mName, l->mName) < 0;
     }
     else {
         return rsize < lsize;
     }
}
    
BOOL cDirWnd::sort_time(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     if(gSortDirUp) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) return strcmp(l->mName, r->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     return difftime(r->mStat.st_mtime, l->mStat.st_mtime) > 0;
}
    
BOOL cDirWnd::sort_time_reverse(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     if(gSortDirUp) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) return strcmp(r->mName, l->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     return difftime(l->mStat.st_mtime, r->mStat.st_mtime) > 0;
}

BOOL cDirWnd::sort_user(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     if(gSortDirUp) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) return strcmp(l->mName, r->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     return r->mLStat.st_uid > l->mLStat.st_uid;
}
    
BOOL cDirWnd::sort_user_reverse(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     if(gSortDirUp) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) return strcmp(r->mName, l->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     return l->mLStat.st_uid > r->mLStat.st_uid;
}

BOOL cDirWnd::sort_group(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     if(gSortDirUp) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) return strcmp(l->mName, r->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     return r->mLStat.st_gid > l->mLStat.st_gid;
}
    
BOOL cDirWnd::sort_group_reverse(void* left, void* right)
{ 
     sFile* l = (sFile*) left;
     sFile* r = (sFile*) right;

     if(strcmp(l->mName, ".") == 0) return TRUE;
     if(strcmp(l->mName, "..") == 0) {
          if(strcmp(r->mName, ".") == 0) return FALSE;

          return TRUE;
     }
     if(strcmp(r->mName, ".") == 0) return FALSE;
     if(strcmp(r->mName, "..") == 0) return FALSE;

     if(gSortDirUp) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) return strcmp(r->mName, l->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     return l->mLStat.st_gid > r->mLStat.st_gid;
}
void cDirWnd::Sort()
{
TBEGIN();

M(("vector %d", vector_size(mFiles)));

    switch(gSortKind)
    {
    case kName:
        vector_sort(mFiles, sort_name);
        break;

    case kNameReverse:
        vector_sort(mFiles, sort_name_reverse);
        break;

    case kExt:
        vector_sort(mFiles, sort_ext);
        break;

    case kExtReverse:
        vector_sort(mFiles, sort_ext_reverse);
        break;

    case kSize:
        vector_sort(mFiles, sort_size);
        break;

    case kSizeReverse:
        vector_sort(mFiles, sort_size_reverse);
        break;

    case kTime:
        vector_sort(mFiles, sort_time);
        break;

    case kTimeReverse:
        vector_sort(mFiles, sort_time_reverse);
        break;

    case kUser:
        vector_sort(mFiles, sort_user);
        break;

    case kUserReverse:
        vector_sort(mFiles, sort_user_reverse);
        break;

    case kGroup:
        vector_sort(mFiles, sort_group);
        break;

    case kGroupReverse:
        vector_sort(mFiles, sort_group_reverse);
        break;
    }

TEND();     
}

void cDirWnd::read()
{
TBEGIN();

    if(access(Path(), F_OK) != 0) Move("/");

    if(strcmp(mPath, mPathBefore) != 0) {
        hash_clear(mMarkFiles);
    }
    
    for(int i=0; i<vector_size(mFiles); i++) {
        delete (sFile*)vector_item(mFiles, i);
    }
    vector_clear(mFiles);

    DIR* dir = opendir(mPath);
    if(dir == NULL) {
        gErrMsgCancel = false; 
        err_msg("cDirWnd::read(): opendir err");
        Move("/");
    }

    bool mask_default = strcmp(mMask, "{*,.*}") == 0;
    
    char glob_cmd[512];
    VALUE glob_array;
    if(!mask_default) {
        char* cwd = mygetcwd();

        bool quote = false;
        const int len = strlen(mPath);
        for(int i=0; i<len; i++) {
            if(mPath[i] == '\'') {
                quote = true;
                break;
            }
        }

        if(quote) 
            sprintf(glob_cmd, "Dir.chdir(\"%s\"); Dir['%s']", mPath, mMask);
        else 
            sprintf(glob_cmd, "Dir.chdir('%s'); Dir['%s']", mPath, mMask);
        glob_array = rb_eval_string(glob_cmd);

        chdir(cwd);
    }
    
    struct dirent* entry;
    while(entry = readdir(dir)) {
        char path[PATH_MAX];
        strcpy(path, mPath);
        strcat(path, entry->d_name);

        struct stat stat_;
        memset(&stat_, 0, sizeof(struct stat));
        stat(path, &stat_);
          
        struct stat lstat_;
        memset(&lstat_, 0, sizeof(struct stat));
        lstat(path, &lstat_);
        
        if(mask_default) {
            if(strcmp(entry->d_name, ".") != 0) {
                /// mark ///
                bool mark = false;
                
                if((int)hash_item(mMarkFiles, entry->d_name) == 1)
                    mark = true;

                /// add ///
                vector_add(mFiles,
                    new sFile(entry->d_name, &stat_, &lstat_, mark));
            }
        }
        else {
            bool found = false;
            for(int i=0; i < RARRAY(glob_array)->len; i++) {
                VALUE file = rb_ary_entry(glob_array, i);

                if(strcmp(RSTRING(file)->ptr, entry->d_name) == 0) {
                    found = true;
                }
            }

            if(strcmp(entry->d_name, ".") != 0 && 
                (strcmp(entry->d_name, "..") == 0 || found))
            {
                /// mark ///
                bool mark = false;
                if((int)hash_item(mMarkFiles, entry->d_name) == 1)
                    mark = true;

                /// add ///
                vector_add(mFiles
                      , new sFile(entry->d_name, &stat_, &lstat_, mark));
            }
        }
    }
    closedir(dir);
    
    strcpy(mPathBefore, mPath);

TEND();     
}

void cDirWnd::Reread()
{
TBEGIN();

    read();
    MoveCursor(mCursor);
    Sort();

TEND();
}

int cDirWnd::CursorX()
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int dstack_exist = vector_size(gDirStack) > 0 ? 1 : 0;
    const int ptty_exist = vector_size(gTty) > 0 ? 1:0;

    if(cDirWnd::gViewOption == kOneDir
        || cDirWnd::gViewOption == kOneDir2
        || cDirWnd::gViewOption == kOneDir3
        || cDirWnd::gViewOption == kOneDir5)
    {
        return mCursor/(maxy-kMaxYMinus-dstack_exist-ptty_exist);
    }
    else {
        return 0;
    }
}

int cDirWnd::CursorY()
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int dstack_exist = vector_size(gDirStack) > 0 ? 1 : 0;
    const int ptty_exist = vector_size(gTty) > 0 ? 1:0;

    if(cDirWnd::gViewOption == kOneDir 
       || cDirWnd::gViewOption == kOneDir2 
       || cDirWnd::gViewOption == kOneDir3
       || cDirWnd::gViewOption == kOneDir5)
    {
         return (mCursor-mScrollTop)
                     % (maxy-kMaxYMinus-dstack_exist-ptty_exist);
    }
    else {
        return mCursor-mScrollTop;
    }
}

int cDirWnd::CursorMaxX()
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int dstack_exist = vector_size(gDirStack) > 0 ? 1 : 0;
    const int ptty_exist = vector_size(gTty) > 0 ? 1:0;

    if(cDirWnd::gViewOption == kOneDir 
        || cDirWnd::gViewOption == kOneDir2 
        || cDirWnd::gViewOption == kOneDir3
        || cDirWnd::gViewOption == kOneDir5)
    {
        return (vector_size(mFiles)-1)
                /(maxy-kMaxYMinus-dstack_exist-ptty_exist) + 1;
    }
    else {
        return 1;
    }
}

int cDirWnd::CursorMaxY()
{
    const int dstack_exist = vector_size(gDirStack) > 0 ? 1 : 0;
    const int ptty_exist = vector_size(gTty) > 0 ? 1:0;
        
    return mgetmaxy() - kMaxYMinus -dstack_exist -ptty_exist;
}

int cDirWnd::Cursor()
{
    return mCursor;
}

int cDirWnd::CursorMax()
{
    return vector_size(mFiles);
}

void cDirWnd::MoveCursor(int index)
{
TBEGIN();

    mCursor = index;
    
    if(mCursor < 0) mCursor = 0;
    if(mCursor >= vector_size(mFiles)) mCursor = vector_size(mFiles)-1;

    rb_funcall(rb_cObject, rb_intern("cursor_move_hook"), 1, INT2FIX(index));

TEND();     
}

int cDirWnd::ScrollTop()
{
    return mScrollTop;
}

void cDirWnd::SetScrollTop(int index)
{
    mScrollTop = index;

    if(mScrollTop < 0) mScrollTop = 0;
    if(mScrollTop >= vector_size(mFiles)) mScrollTop = vector_size(mFiles)-1;
}

bool cDirWnd::IsLeftDir()
{
    return this == gLDir;
}

bool cDirWnd::IsRightDir()
{
    return this != gLDir;
}

void cDirWnd::Activate(cDirWnd* current)
{
TBEGIN();

    current->mActive = false;
    mActive = true;

    if(!gIndividualCursor)
        MoveCursor(mScrollTop + current->mCursor - current->mScrollTop);

    chdir(mPath);

TEND();     
}

sFile* cDirWnd::CursorFile()
{
    return (sFile*)vector_item(mFiles, mCursor);
}

sFile* cDirWnd::File(int num)
{
    if(num>=0 && num<vector_size(mFiles)) {
        return (sFile*)vector_item(mFiles, num);
    }

    return NULL;
}

void cDirWnd::Mark()
{
TBEGIN();

    sFile* cursor = (sFile*)vector_item(mFiles, mCursor);
    cursor->mMark = !cursor->mMark;

    if(cursor->mMark)
        hash_put(mMarkFiles, cursor->mName, (void*)1);
    else
        hash_erase(mMarkFiles, cursor->mName);

    
TEND();     
}

void cDirWnd::Mark2(int index)
{
TBEGIN();

    if(index>=0 && index<vector_size(mFiles)) {
        sFile* cursor = (sFile*)vector_item(mFiles, index);
        cursor->mMark = !cursor->mMark;

        if(cursor->mMark)
            hash_put(mMarkFiles, cursor->mName, (void*)1);
        else
            hash_erase(mMarkFiles, cursor->mName);
    }

    
TEND();     
}

void cDirWnd::Mark3(int index)
{
TBEGIN();

    if(index>=0 && index<vector_size(mFiles)) {
        sFile* cursor = (sFile*)vector_item(mFiles, index);
        cursor->mMark = true;

        if(cursor->mMark)
            hash_put(mMarkFiles, cursor->mName, (void*)1);
        else
            hash_erase(mMarkFiles, cursor->mName);
    }

    
TEND();     
}

void cDirWnd::MarkOff(int index)
{
TBEGIN();

    if(index>=0 && index<vector_size(mFiles)) {
        sFile* cursor = (sFile*)vector_item(mFiles, index);
        cursor->mMark = false;

        if(cursor->mMark)
            hash_put(mMarkFiles, cursor->mName, (void*)1);
        else
            hash_erase(mMarkFiles, cursor->mName);
    }

    
TEND();     
}

void cDirWnd::MarkAll()
{
TBEGIN();

    for(int i=0; i<vector_size(mFiles); i++) {
        sFile* file = (sFile*)vector_item(mFiles, i);
        if(strcmp(file->mName, ".") != 0 && strcmp(file->mName, "..") != 0) {
            file->mMark = !file->mMark;

            if(file->mMark)
                hash_put(mMarkFiles, file->mName, (void*)1);
            else
                hash_erase(mMarkFiles, file->mName);
        }
    }

TEND();     
}

void cDirWnd::MarkAllFiles()
{
TBEGIN();

    for(int i=0; i<vector_size(mFiles); i++) {
        sFile* file = (sFile*)vector_item(mFiles, i);
        if(!S_ISDIR(file->mStat.st_mode)) {
             file->mMark = !file->mMark;

             if(file->mMark)
                 hash_put(mMarkFiles, file->mName, (void*)1);
             else
                 hash_erase(mMarkFiles, file->mName);
        }
    }

TEND();     
}

void cDirWnd::ResetMarks()
{
TBEGIN();

    for(int i=0; i<vector_size(mFiles); i++) {
        sFile* file = (sFile*)vector_item(mFiles, i);
        file-> mMark = false;

//        hash_erase(mMarkFiles, file->mName);
    }
    
    hash_clear(mMarkFiles);

TEND();
}

bool cDirWnd::Marking()
{
    for(int i=0; i<vector_size(mFiles); i++) {
        sFile* file = (sFile*)vector_item(mFiles, i);
        if(file->mMark) return true;
    }

    return false;
}

VALUE cDirWnd::MarkFiles()
{
TBEGIN();

    VALUE result = rb_ary_new();

    if(Marking()) {
        for(int i=0; i<vector_size(mFiles); i++) {
            sFile* file = (sFile*)vector_item(mFiles, i);
            if(file->mMark) {
                rb_ary_push(result, rb_str_new2(file->mName));
            }
        }
    }
    else {
        if(ActiveDir() == this) {
            rb_ary_push(result, rb_str_new2(ActiveDir()->CursorFile()->mName));
        }
    }

    return result;

TEND();     
}

ALLOCATED string_obj* cDirWnd::MarkFilesSQuote()
{
TBEGIN();

    string_obj* result = string_new("");

    if(Marking()) {
        for(int i=0; i<vector_size(mFiles); i++) {
            sFile* file = (sFile*)vector_item(mFiles, i);

            /// is there a single quote char in file name? ///
            bool squote_name = false;
            const int len = strlen(file->mName);
            for(int i=0; i<len; i++) {
                if(file->mName[i] == '\'') {
                    squote_name = true;
                    break;
                }
            }

            if(squote_name) {
                if(file->mMark) {
                    string_push_back(result, "\"");
                    string_push_back(result, file->mName);
                    string_push_back(result, "\" ");
                }
            }
            else {
                if(file->mMark) {
                    string_push_back(result, "'");
                    string_push_back(result, file->mName);
                    string_push_back(result, "' ");
                }
            }
        }
    }
    else {
        if(ActiveDir() == this) {
            string_push_back(result, "'");
            string_push_back(result, ActiveDir()->CursorFile()->mName);
            string_push_back(result, "'");
        }
    }

TEND();

    return result;
}

int cDirWnd::MarkFileNum()
{
    int result = 0;
    for(int i=0; i<vector_size(mFiles); i++) {
        sFile* file = (sFile*)vector_item(mFiles, i);

        if(file->mMark) {
            result++;
        }
    }

    return result;
}

int cDirWnd::MarkFileSize()
{
    int size = 0;
    for(int i=0; i<vector_size(mFiles); i++) {
        sFile* file = (sFile*)vector_item(mFiles, i);

        if(file->mMark && !S_ISDIR(file->mStat.st_mode)) {
            size += file->mStat.st_size;
        }
    }

    return size;
}

bool cDirWnd::check_path(char* new_path)
{
    bool result = false;

    DIR* dir = opendir(new_path);
    if(dir) {
        result = true;
        closedir(dir);
    }

    return result;   
}

void cDirWnd::Move(char* path)
{
TBEGIN();

    char path2[PATH_MAX];
    if(!correct_path(path, path2)) {
        //strcpy(path2, "/");
        return;
    }
    
    if(access(path2, F_OK) == 0 && strcmp(mPath, path2) != 0) {
         char path3[PATH_MAX];

         strcpy(path3, path2);
         if(path2[strlen(path2) -1] != '/') {
              strcat(path3, "/");
         }

         if(check_path(path3)) {
             sDirInfo* dinfo = (sDirInfo*)MALLOC(sizeof(sDirInfo));
             strcpy(dinfo->mPath, mPath);
             dinfo->mCursor = mCursor;
             dinfo->mScrollTop = mScrollTop;
             
             list_push_back(mDirStack, dinfo);
             if(list_size(mDirStack) > kDirStackSize) {
                 FREE(list_item(list_begin(mDirStack)));
                 list_pop_front(mDirStack);
             }
             
             char* tmp = STRDUP(mPath);
             char* fname = STRDUP(basename(tmp));
             FREE(tmp);
    
             char* parentpath = parentname(mPath);

             strcpy(mPath, path3);
             read();
             Sort();

             if(strcmp(mPath, parentpath) == 0) {
                 bool found = false;
                     
                 for(int i=0; i<vector_size(mFiles); i++) {
                     sFile* file = (sFile*)vector_item(mFiles, i);
                     if(strcmp(file->mName, fname) == 0) {
                         mScrollTop = 0;
                         MoveCursor(i);
                         found = true;
                     }
                 }
                 
                 if(!found) {
                     mScrollTop = 0;
                     MoveCursor(0);
                 }
             }
             else {
                 if(gRemainCursor) {
                     bool found = false;
                     for(list_it* i = list_last(mDirStack); i;
                                 i = list_prev(i))
                         {
                         sDirInfo* dinfo = (sDirInfo*)list_item(i);
    
                         if(strcmp(mPath, dinfo->mPath) == 0) {
                             SetScrollTop(dinfo->mScrollTop);
                             MoveCursor(dinfo->mCursor);
                             found = true;
                             break;
                         }
                     }
        
                     if(!found) {
                         mScrollTop = 0;
                         MoveCursor(0);
                     }
                }
                else {
                    mScrollTop = 0;
                    MoveCursor(0);
                }
             }
                 
             FREE(parentpath);
             FREE(fname);
             
             if(this == ActiveDir())  chdir(mPath);
         }
    }
    
TEND();    
}

void cDirWnd::MoveBack()
{
TBEGIN();

    if(list_size(mDirStack) > 0) {
        sDirInfo* dinfo = (sDirInfo*)list_pop_back(mDirStack);

        if(access(dinfo->mPath, F_OK) == 0) {
             strcpy(mPath, dinfo->mPath);
             read();

             Sort();
    
             SetScrollTop(dinfo->mScrollTop);
             MoveCursor(dinfo->mCursor);
        }

        FREE(dinfo);
    }

    if(ActiveDir() == this) chdir(mPath);

TEND();    
}

bool cDirWnd::ChangeMask(char* mask)
{
    strcpy(mMask, mask);

    MoveCursor(mCursor);
    SetScrollTop(0);

    Reread();

    return true;
}
    
void cDirWnd::SelectDirInput(int meta, int key)
{
    if(key == 14 || key == KEY_DOWN || key == 9) {    // CTRL-N CTRL-I
        gDirCursor++;
    }
    else if(key == 16 || key == KEY_UP) {    //CTRL-P
        gDirCursor--;
    }
    else if(key == 6 || key == KEY_RIGHT) {    // CTRL-F
        gDirCursor++;
    }
    else if(key == 2 || key == KEY_LEFT) {    // CTRL-B
        gDirCursor--;
    }
    else if(key == 10 || key == 13) {		// CTRL-J CTRL-M
        PushFrontDir();
        
        sDirInfo* dinfo = (sDirInfo*)vector_item(gDirStack, gDirCursor+1);
        
        Move((char*)dinfo->mPath);
        SetScrollTop(dinfo->mScrollTop);
        MoveCursor(dinfo->mCursor);
        
        FREE(dinfo);
        vector_erase(gDirStack, gDirCursor+1);
        
        gSelectDir = false;
    }
    else if(key == 4 || key == KEY_NPAGE) {    // CTRL-D
        gDirCursor+=5;
    }
    else if(key == 21 || key == KEY_PPAGE) {    // CTRL-U
        gDirCursor-=5;
    }
    else if(key == 3 || key == 7 || key == 27 || key == 8 || key == KEY_BACKSPACE || key == 127 || key == KEY_DC) { // CTRL-C CTRL-G Escape Bs
        gSelectDir = false;
    }
    
    if(gDirCursor < 0) {
        gDirCursor = vector_size(gDirStack)-1;
    }
    if(gDirCursor >= vector_size(gDirStack)) {
        gDirCursor = 0;
//        gDirCursor = vector_size(gDirStack)-1;
    }

    const int maxy = mgetmaxy();
    if(gDirCursor < gDirScrollTop) {
        gDirScrollTop = (gDirCursor/(maxy-2))*(maxy-2);
    }
    if(gDirCursor > gDirScrollTop + maxy-3) {
        gDirScrollTop = (gDirCursor/(maxy-2))    *(maxy-2);
    }
}

void cDirWnd::SelectDirView()
{
    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    mbox(0,0, maxx, maxy);
    
    for(int i=gDirScrollTop; i<vector_size(gDirStack) && i-gDirScrollTop<maxy-2; i++)
    {
        char* item = ((sDirInfo*)vector_item(gDirStack, i))->mPath;
            
        char buf[PATH_MAX];
        if(gKanjiCode == kUtf)
            str_cut2(item, maxx-2, buf, PATH_MAX);
        else
            cut(item, buf, maxx-2);

        if(gDirCursor == i) mattron(kCAReverse);
        mmvprintw(i-gDirScrollTop+1, 1, "%s", buf);
        if(gDirCursor == i) mattroff();
    }

    mrefresh();
}

void cDirWnd::View()
{
TBEGIN();

    const int maxx = mgetmaxx();
    const int maxy = mgetmaxy();

    const int dstack_exist = vector_size(gDirStack) > 0 ? 1 : 0;
    const int ptty_exist = vector_size(gTty) > 0 ? 1:0;

    /// view one dir ///
    if(cDirWnd::gViewOption == kOneDir) {
        if(mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-ptty_exist);

            char path[256];
            strcpy(path, mPath);
            strcat(path, mMask);

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                if(gKanjiCode == kUtf) {
                    char buf[256];

                    str_cut3(path, maxx-4, buf, 256);

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
                else {
                    bool kanji[256];
                    for(int i=0; i<len; i++) {
                        if(is_kanji(path[i])) {
                            kanji[i] = true;
                            i++;
                            kanji[i] = false;
                        }
                        else {
                            kanji[i] = false;
                        }
                    }

                    char buf[256];
                    if(kanji[len-(maxx-4)-1]) {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                        buf[0] = ' ';
                    }
                    else {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                    }

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
            }

            for(int i=mScrollTop;
                i-mScrollTop<maxy-kMaxYMinus -dstack_exist -ptty_exist
                            && i<vector_size(mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(mFiles, i);
                 
                if(mCursor == i && mActive) {
                     attr |= kCAReverse;
                }

                char fname[256];
                if(file->mMark) {
                     strcpy(fname, "*");

                     if(gColor)
                         attr |= gColorMark;
                     else 
                         attr |= kCABold;
                }
                else {
                     strcpy(fname, " ");
                }
        
                strcat(fname, file->mName);

                if(S_ISDIR(file->mStat.st_mode)) {
                     strcat(fname, "/");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorDir;
                     }
                     else {
                         if(gBoldDir) attr |= kCABold;
                     }
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     strcat(fname, "*");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorExe;
                     }
                     else {
                         if(gBoldExe) attr |= kCABold;
                     }
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    strcat(fname, "@");
                
                    if(gColor && !file->mMark) attr |= gColorLink;
                }

                if(S_ISLNK(file->mLStat.st_mode)) {
                    char link[PATH_MAX + 1];

                    char path[PATH_MAX];
                    strcpy(path, Path());
                    strcat(path, file->mName);                 
                     
                    int bytes = readlink(path, link, PATH_MAX);
                    link[bytes] = 0;
                    sprintf(fname + strlen(fname), " -> %s", link);
                }

                char permission[12];
                strcpy(permission, "----------");
                if(S_ISDIR(file->mLStat.st_mode)) permission[0] = 'd';
                if(S_ISLNK(file->mLStat.st_mode)) permission[0] = 'l';
            
                mode_t smode = file->mLStat.st_mode;
                if(smode & S_IRUSR) permission[1] = 'r';
                if(smode & S_IWUSR) permission[2] = 'w';
                if(smode & S_IXUSR) permission[3] = 'x';
                if(smode & S_IRGRP) permission[4] = 'r';
                if(smode & S_IWGRP) permission[5] = 'w';
                if(smode & S_IXGRP) permission[6] = 'x';
                if(smode & S_IROTH) permission[7] = 'r';
                if(smode & S_IWOTH) permission[8] = 'w';
                if(smode & S_IXOTH) permission[9] = 'x';
                if(smode & S_ISUID) permission[3] = 's';
                if(smode & S_ISGID) permission[6] = 's';
#if defined(S_ISTXT)
                if(smode & S_ISTXT) permission[9] = 't';
#endif
#if defined(S_ISVTX)
                if(smode & S_ISVTX) permission[9] = 't';
#endif
        
                time_t t = file->mLStat.st_mtime;
                struct tm* tm_ = (struct tm*)localtime(&t);

                mattron(attr);
                
                if(gViewNameOnly) {
                    char name[256];

                    if(gKanjiCode == kUtf)
                        str_cut2(fname, maxx-3, name, 256);
                    else
                        cut(fname, name, maxx-3);
            
                    mmvprintw(i-mScrollTop + 1 + dstack_exist, 1, "%s", name);
                }
                else {               
                    char buf[256];

                    if(gKanjiCode == kUtf)
                        str_cut2(fname, maxx-61, buf, 256);
                    else 
                        cut(fname, buf, maxx-61);
    
                    char owner[256];
                    char* tmp = mygetpwuid(&file->mLStat);
                    if(tmp) {
                        if(gKanjiCode == kUtf)
                            str_cut2(tmp, 8, owner, 256);
                        else
                            cut(tmp, owner, 8);
                    }
                    else {
                        sprintf(owner, "%d", file->mLStat.st_uid);
                    }
    
                    char group[256];
                    tmp = mygetgrgid(&file->mLStat);
                    if(tmp) {
                        if(gKanjiCode == kUtf)
                            str_cut2(tmp, 8, group, 256);
                        else
                            cut(tmp, group, 8);
                    }
                    else {
                        sprintf(group, "%d", file->mLStat.st_gid);
                    }
    
    
                    int year = tm_->tm_year-100;
                    if(year < 0) year+=100;
                    while(year > 100) year-=100;
    
    
                    if(file->mStat.st_size > 999999999) {
                        sprintf(buf + strlen(buf)
                                   , " %s %3d %-8s %-8s999999999 %02d-%02d-%02d %02d:%02d "
                           , permission, file->mStat.st_nlink
                           , owner, group
                           
                           , year, tm_->tm_mon+1
                           , tm_->tm_mday, tm_->tm_hour, tm_->tm_min
                        );
                    }
                    else if(S_ISDIR(file->mStat.st_mode)) {
                        sprintf(buf + strlen(buf)
                           , " %s %3d %-8s %-8s    <DIR> %02d-%02d-%02d %02d:%02d "
                           , permission, file->mStat.st_nlink
                           , owner, group
                           
                           , year, tm_->tm_mon+1
                           , tm_->tm_mday, tm_->tm_hour, tm_->tm_min
                        );
                    }
                    else {
                        sprintf(buf + strlen(buf)
                           , " %s %3d %-8s %-8s%9lld %02d-%02d-%02d %02d:%02d "
                           , permission, file->mStat.st_nlink
                           , owner, group
                           
                           , file->mStat.st_size
                           
                           , year, tm_->tm_mon+1
                           , tm_->tm_mday, tm_->tm_hour, tm_->tm_min
                        );
                    }
            
                    mmvprintw(i-mScrollTop + 1 + dstack_exist, 1, "%s", buf);
                }
                
                mattroff();
            }

            const int p = (((float)mCursor+1)/((float)vector_size(mFiles)))*100;
            
            mmvprintw(maxy - kMaxYMinus+1 -ptty_exist, 2
                    , "(%d/%d)-%dbytes-(%3d%%)", MarkFileNum(), vector_size(mFiles), MarkFileSize(), p);
       }
    }
    else if(cDirWnd::gViewOption == kOneDir2) {
        if(mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-ptty_exist);

            char path[256];
            strcpy(path, mPath);
            strcat(path, mMask);

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                if(gKanjiCode == kUtf) {
                    char buf[256];

                    str_cut3(path, maxx-4, buf, 256);

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
                else {
                    bool kanji[256];
                    for(int i=0; i<len; i++) {
                        if(is_kanji(path[i])) {
                            kanji[i] = true;
                            i++;
                            kanji[i] = false;
                        }
                        else {
                            kanji[i] = false;
                        }
                    }

                    char buf[256];
                    if(kanji[len-(maxx-4)-1]) {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                        buf[0] = ' ';
                    }
                    else {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                    }

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
            }

            for(int i=mScrollTop;
                i-mScrollTop<(maxy-kMaxYMinus-dstack_exist-ptty_exist)*2
                            && i<vector_size(mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(mFiles, i);
                 
                if(mCursor == i && mActive) {
                     attr |= kCAReverse;
                }

                char fname[256];
                if(file->mMark) {
                     strcpy(fname, "*");

                     if(gColor)
                         attr |= gColorMark;
                     else 
                         attr |= kCABold;
                }
                else {
                     strcpy(fname, " ");
                }
        
                strcat(fname, file->mName);

                if(S_ISDIR(file->mStat.st_mode)) {
                     strcat(fname, "/");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorDir;
                     }
                     else {
                         if(gBoldDir) attr |= kCABold;
                     }
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     strcat(fname, "*");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorExe;
                     }
                     else {
                         if(gBoldExe) attr |= kCABold;
                     }
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    strcat(fname, "@");
                
                    if(gColor && !file->mMark) attr |= gColorLink;
                }

                if(S_ISLNK(file->mLStat.st_mode)) {
                    char link[PATH_MAX + 1];

                    char path[PATH_MAX];
                    strcpy(path, Path());
                    strcat(path, file->mName);                 
                     
                    int bytes = readlink(path, link, PATH_MAX);
                    link[bytes] = 0;
                    sprintf(fname + strlen(fname), " -> %s", link);
                }

                mattron(attr);
                const int x = (i-mScrollTop)
                                /(maxy-kMaxYMinus-dstack_exist-ptty_exist)
                                *(maxx/2) + 1;
                const int y = (i-mScrollTop)
                                %(maxy-kMaxYMinus-dstack_exist-ptty_exist)
                                    + 1 + dstack_exist;

                if(gViewNameOnly) {
                    char name[256];

                    if(gKanjiCode == kUtf)
                        str_cut2(fname, maxx/2-3, name, 256);
                    else
                        cut(fname, name, maxx/2-3);

                    mmvprintw(y, x, "%s", name);
                }
                else {
                    char buf[256];

                    char name[256];
                    if(gKanjiCode == kUtf)
                        str_cut2(fname, maxx/2-28, name, 256);
                    else
                        cut(fname, name, maxx/2-28);
    
                    time_t t = file->mLStat.st_mtime;
                    struct tm* tm_ = (struct tm*)localtime(&t);
    
                    int year = tm_->tm_year-100;
                    if(year < 0) year+=100;
                    while(year > 100) year-=100;
    
                    if(file->mStat.st_size > 999999999) {
                        sprintf(buf, "%s999999999 %02d-%02d-%02d %02d:%02d "
                             , name, year
                             , tm_->tm_mon+1, tm_->tm_mday, tm_->tm_hour
                             , tm_->tm_min);
                    }
                    else if(S_ISDIR(file->mStat.st_mode)) {
                        sprintf(buf, "%s    <DIR> %02d-%02d-%02d %02d:%02d "
                             , name, year
                             , tm_->tm_mon+1, tm_->tm_mday, tm_->tm_hour
                             , tm_->tm_min);
                    }
                    else {
                        sprintf(buf, "%s%9lld %02d-%02d-%02d %02d:%02d "
                             , name, file->mStat.st_size, year
                             ,  tm_->tm_mon+1, tm_->tm_mday, tm_->tm_hour
                             , tm_->tm_min);
                    }
                                          
                    mmvprintw(y, x, "%s", buf);
                }
                mattroff();
            }

            const int p = (((float)mCursor+1)/((float)vector_size(mFiles)))*100;
            
            mmvprintw(maxy - kMaxYMinus+1 -ptty_exist, 2
                    , "(%d/%d)-%dbytes-(%3d%%)", MarkFileNum(), vector_size(mFiles), MarkFileSize(), p);
        }
    }
    else if(cDirWnd::gViewOption == kOneDir3) {
        if(mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-ptty_exist);

            char path[256];
            strcpy(path, mPath);
            strcat(path, mMask);

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                if(gKanjiCode == kUtf) {
                    char buf[256];

                    str_cut3(path, maxx-4, buf, 256);

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
                else {
                    bool kanji[256];
                    for(int i=0; i<len; i++) {
                        if(is_kanji(path[i])) {
                            kanji[i] = true;
                            i++;
                            kanji[i] = false;
                        }
                        else {
                            kanji[i] = false;
                        }
                    }

                    char buf[256];
                    if(kanji[len-(maxx-4)-1]) {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                        buf[0] = ' ';
                    }
                    else {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                    }

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
            }

            for(int i=mScrollTop;
                i-mScrollTop<(maxy-kMaxYMinus-dstack_exist-ptty_exist)*3
                            && i<vector_size(mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(mFiles, i);
                 
                if(mCursor == i && mActive) {
                     attr |= kCAReverse;
                }

                char fname[256];
                if(file->mMark) {
                     strcpy(fname, "*");

                     if(gColor)
                         attr |= gColorMark;
                     else 
                         attr |= kCABold;
                }
                else {
                     strcpy(fname, " ");
                }
        
                strcat(fname, file->mName);

                if(S_ISDIR(file->mStat.st_mode)) {
                     strcat(fname, "/");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorDir;
                     }
                     else {
                         if(gBoldDir) attr |= kCABold;
                     }
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     strcat(fname, "*");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorExe;
                     }
                     else {
                         if(gBoldExe) attr |= kCABold;
                     }
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    strcat(fname, "@");
                
                    if(gColor && !file->mMark) attr |= gColorLink;
                }

                if(S_ISLNK(file->mLStat.st_mode)) {
                    char link[PATH_MAX + 1];

                    char path[PATH_MAX];
                    strcpy(path, Path());
                    strcat(path, file->mName);                 
                     
                    int bytes = readlink(path, link, PATH_MAX);
                    link[bytes] = 0;
                    sprintf(fname + strlen(fname), " -> %s", link);
                }

                mattron(attr);
                const int x = (i-mScrollTop)
                                /(maxy-kMaxYMinus-dstack_exist-ptty_exist)
                                *(maxx/3) + 1;
                const int y = (i-mScrollTop)
                                %(maxy-kMaxYMinus-dstack_exist-ptty_exist)
                                    + 1 + dstack_exist;

                if(gViewNameOnly) {
                    char name[256];

                    if(gKanjiCode == kUtf)
                        str_cut2(fname, maxx/3-3, name, 256);
                    else
                        cut(fname, name, maxx/3-3);
                
                    mmvprintw(y, x, "%s", name);                    
                }
                else {
                    char buf[256];

                    char name[256];
                    if(gKanjiCode == kUtf)
                        str_cut2(fname, maxx/3-13, name, 256);
                    else
                        cut(fname, name, maxx/3-13);

                    if(file->mStat.st_size > 999999999) {
                        sprintf(buf, "%s999999999 ", name);
                    }
                    else if(S_ISDIR(file->mStat.st_mode)) {
                        sprintf(buf, "%s    <DIR> ", name);
                    }
                    else {
                        sprintf(buf, "%s%9lld ", name, file->mStat.st_size);
                    }
                                          
                    mmvprintw(y, x, "%s", buf);
                }
                mattroff();
            }

            const int p = (((float)mCursor+1)/((float)vector_size(mFiles)))*100;
            
            mmvprintw(maxy - kMaxYMinus+1 -ptty_exist, 2
                    , "(%d/%d)-%dbytes-(%3d%%)", MarkFileNum(), vector_size(mFiles), MarkFileSize(), p);
        }
    }
    
    else if(cDirWnd::gViewOption == kOneDir5) {
        if(mActive) {
            mbox(dstack_exist, 0, maxx-1, maxy-2-dstack_exist-ptty_exist);

            char path[256];
            strcpy(path, mPath);
            strcat(path, mMask);

            const int len = strlen(path);
            if(len < maxx-4) {
                mattron(kCABold);
                mmvprintw(0 + dstack_exist, 2, "%s", path);
                mattroff();
            }
            else {
                if(gKanjiCode == kUtf) {
                    char buf[256];

                    str_cut3(path, maxx-4, buf, 256);

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
                else {
                    bool kanji[256];
                    for(int i=0; i<len; i++) {
                        if(is_kanji(path[i])) {
                            kanji[i] = true;
                            i++;
                            kanji[i] = false;
                        }
                        else {
                            kanji[i] = false;
                        }
                    }

                    char buf[256];
                    if(kanji[len-(maxx-4)-1]) {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                        buf[0] = ' ';
                    }
                    else {
                        int i;
                        for(i=len-(maxx-4); i<len; i++) {
                            buf[i-len+(maxx-4)] = path[i];
                        }
                        buf[i-len+(maxx-4)] = 0;
                    }

                    mattron(kCABold);
                    mmvprintw(0 + dstack_exist, 2, "%s", buf);
                    mattroff();
                }
            }

            for(int i=mScrollTop;
                i-mScrollTop<(maxy-kMaxYMinus-dstack_exist-ptty_exist)*5
                            && i<vector_size(mFiles);
                i++)
            {
                int attr = 0;
                sFile* file = (sFile*)vector_item(mFiles, i);
                 
                if(mCursor == i && mActive) {
                     attr |= kCAReverse;
                }

                char fname[256];
                if(file->mMark) {
                     strcpy(fname, "*");

                     if(gColor)
                         attr |= gColorMark;
                     else 
                         attr |= kCABold;
                }
                else {
                     strcpy(fname, " ");
                }
        
                strcat(fname, file->mName);

                if(S_ISDIR(file->mStat.st_mode)) {
                     strcat(fname, "/");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorDir;
                     }
                     else {
                         if(gBoldDir) attr |= kCABold;
                     }
                }
                else if(file->mStat.st_mode&S_IXUSR
                            || file->mStat.st_mode&S_IXGRP
                            || file->mStat.st_mode&S_IXGRP)
                {
                     strcat(fname, "*");

                     if(gColor) {
                         if(!file->mMark) attr |= gColorExe;
                     }
                     else {
                         if(gBoldExe) attr |= kCABold;
                     }
                }
                else if(S_ISLNK(file->mLStat.st_mode)) {
                    strcat(fname, "@");
                
                    if(gColor && !file->mMark) attr |= gColorLink;
                }

                if(S_ISLNK(file->mLStat.st_mode)) {
                    char link[PATH_MAX + 1];

                    char path[PATH_MAX];
                    strcpy(path, Path());
                    strcat(path, file->mName);                 
                     
                    int bytes = readlink(path, link, PATH_MAX);
                    link[bytes] = 0;
                    sprintf(fname + strlen(fname), " -> %s", link);
                }

                char buf[256];

                char name[256];
                if(gKanjiCode == kUtf)
                    str_cut2(fname, maxx/5-4, name, 256);
                else
                    cut(fname, name, maxx/5-4);

                sprintf(buf, "%s ", name);
                                          
                mattron(attr);
                const int x = (i-mScrollTop)
                                /(maxy-kMaxYMinus-dstack_exist-ptty_exist)
                                *(maxx/5) + 1;
                const int y = (i-mScrollTop)
                                %(maxy-kMaxYMinus-dstack_exist-ptty_exist)
                                    + 1 + dstack_exist;
                mmvprintw(y, x, "%s", buf);
                mattroff();
            }

            const int p = (((float)mCursor+1)/((float)vector_size(mFiles)))*100;
            
            mmvprintw(maxy - kMaxYMinus+1 -ptty_exist, 2
                    , "(%d/%d)-%dbytes-(%3d%%)", MarkFileNum(), vector_size(mFiles), MarkFileSize(), p);
        }
    }
    
    /// view_all ///
    else {
        int x;
        if(this == gLDir)
            x = 0;
        else
            x = maxx / 2; 

        int line = 0;
        mbox(dstack_exist, x, maxx/2-1, maxy-2-dstack_exist-ptty_exist);

        char path[256];
        strcpy(path, mPath);
        strcat(path, mMask);

        const int len = strlen(path);
        if(len < maxx/2-5) {
            if(mActive) mattron(kCABold);
            mmvprintw(0 + dstack_exist, x+2, "%s", path);
            if(mActive) mattroff();
        }
        else {
            if(gKanjiCode == kUtf) {
                char buf[256];

                str_cut3(path, maxx/2-5, buf, 256);

                if(mActive) mattron(kCABold);
                mmvprintw(0 + dstack_exist, x+2, "%s", buf);
                if(mActive) mattroff();
            }
            else {
                bool kanji[256];
                for(int i=0; i<len; i++) {
                    if(is_kanji(path[i])) {
                        kanji[i] = true;
                        i++;
                        kanji[i] = false;
                    }
                    else {
                        kanji[i] = false;
                    }
                }

                char buf[256];
                if(kanji[len-(maxx/2-5)-1]) {
                    int i;
                    for(i=len-(maxx/2-5); i<len; i++) {
                        buf[i-len+(maxx/2-5)] = path[i];
                    }
                    buf[i-len+(maxx/2-5)] = 0;
                    buf[0] = ' ';
                }
                else {
                    int i;
                    for(i=len-(maxx/2-5); i<len; i++) {
                        buf[i-len+(maxx/2-5)] = path[i];
                    }
                    buf[i-len+(maxx/2-5)] = 0;
                }

                if(mActive) mattron(kCABold);
                mmvprintw(0 + dstack_exist, x+2, "%s", buf);
                if(mActive) mattroff();
            }
        }


        for(int i=mScrollTop;
                i-mScrollTop<maxy-kMaxYMinus-dstack_exist-ptty_exist
                        && i<vector_size(mFiles);
                i++)
            {
            int attr = 0;
            sFile* file = (sFile*)vector_item(mFiles, i);
                 
            if(mCursor == i && mActive) attr |= kCAReverse;

            char fname[256];
            if(file->mMark) {
                strcpy(fname, "*");
                if(gColor)
                    attr |= gColorMark;
                else
                    attr |= kCABold;
            }
            else {
                strcpy(fname, " ");
            }
        
            strcat(fname, file->mName);
        
            if(S_ISDIR(file->mStat.st_mode)) {
                strcat(fname, "/");

                if(gColor) {
                    if(!file->mMark) attr |= gColorDir;
                }
                else {
                    if(gBoldDir) attr |= kCABold;
                }
            }
            else if(file->mStat.st_mode&S_IXUSR
                    || file->mStat.st_mode&S_IXGRP
                    || file->mStat.st_mode&S_IXGRP)
            {
                strcat(fname, "*");

                if(gColor)  {
                    if(!file->mMark) attr |= gColorExe;
                }
                else {
                    if(gBoldExe) attr |= kCABold;
                }
            }
            else if(S_ISLNK(file->mLStat.st_mode)) {
                strcat(fname, "@");
                
                if(gColor && !file->mMark) attr |= gColorLink;
            }

            if(S_ISLNK(file->mLStat.st_mode)) {
                char link[PATH_MAX + 1];

                char path[PATH_MAX];
                strcpy(path, Path());
                strcat(path, file->mName);                 
                 
                int bytes = readlink(path, link, PATH_MAX);
                link[bytes] = 0;
                sprintf(fname + strlen(fname), " -> %s", link);
            }

            /// view nameonly ///
            mattron(attr);
            if(gViewNameOnly) {
                char name[256];
                if(gKanjiCode == kUtf)
                    str_cut2(fname, maxx/2-3, name, 256);
                else
                    cut(fname, name, maxx/2-3);
                
                mmvprintw(i-mScrollTop + 1 + dstack_exist, x + 1, "%s", name);
            }
            /// view_all ///
            else {
                char buf[256];

                char name[256];
                if(gKanjiCode == kUtf)
                    str_cut2(fname, maxx/2-28, name, 256);
                else
                    cut(fname, name, maxx/2-28);

//M(("fname (%s)", fname));
//M(("name (%s)", name));

                time_t t = file->mLStat.st_mtime;
                struct tm* tm_ = (struct tm*)localtime(&t);

                int year = tm_->tm_year-100;
                if(year < 0) year+=100;
                while(year > 100) year-=100;

                if(file->mStat.st_size > 999999999) {
                    sprintf(buf, "%s999999999 %02d-%02d-%02d %02d:%02d "
                         , name, year
                         , tm_->tm_mon+1, tm_->tm_mday, tm_->tm_hour
                         , tm_->tm_min);
                }
                else if(S_ISDIR(file->mStat.st_mode)) {
                    sprintf(buf, "%s    <DIR> %02d-%02d-%02d %02d:%02d "
                         , name, year
                         , tm_->tm_mon+1, tm_->tm_mday, tm_->tm_hour
                         , tm_->tm_min);
                }
                else {
                    sprintf(buf, "%s%9lld %02d-%02d-%02d %02d:%02d "
                         , name, file->mStat.st_size, year
                         , tm_->tm_mon+1, tm_->tm_mday, tm_->tm_hour
                         , tm_->tm_min);
                }
                                          
                mmvprintw(i-mScrollTop + 1 + dstack_exist, x + 1, "%s", buf);
            }
            mattroff();
        }

        mmvprintw(maxy - kMaxYMinus+1 -ptty_exist, x + 2
                    , "(%d/%d)-%dbytes", MarkFileNum(), vector_size(mFiles), MarkFileSize());
        
        if(mActive) {
            const int p = (((float)mCursor+1)/((float)vector_size(mFiles)))*100;
            
            mprintw("-(%3d%%)", p);
        }
    }

    /// draw gDirStack ///
    if(dstack_exist) {
        const int width = maxx / 5;
        int j = 0;
        for(int i=0; i<vector_size(gDirStack); i++) {
            char* item = (char*)vector_item(gDirStack, i);
            
            char item2[256];
            strcpy(item2, "");
            const int len2 = strlen(item);
            for(int k=len2-2; k>=0; k--) {
                if(item[k] == '/') {
                    int l;
                    for(l=k+1; l<len2-1; l++) {
                        item2[l-k-1] = item[l];
                    }
                    item2[l-k-1] = 0;
                    break;
                }
            }
            
            if(j > 4) break;
           /* 
            char buf[256];
            buf[0] = '[';
            buf[1] = '%';
            sprintf(buf + 2, "-%ds]", width-2);

            char buf2[256];
            if(gKanjiCode == kUtf)
                str_cut2(item2, width-2, buf2, 256);
            else
                cut(item2, buf2, width-2);
*/
            char buf2[256];
            if(gKanjiCode == kUtf)
                str_cut2(item2, width-6, buf2, 256);
            else
                cut(item2, buf2, width-6);
            
            char buf[256];
            sprintf(buf, "[%d.%s]", j+1, buf2);

            mmvprintw(0, width * j, "%s", buf);
            j++;                        
        }
    }

TEND(); 
}
