#include "common.h"
#include <strings.h>
#include <time.h>

///////////////////////////////////////////////////////////////////////////////
// ソート
///////////////////////////////////////////////////////////////////////////////
cDirWnd* gCurrentDir = NULL;

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

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(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }

    if(gSortDirUp == Qtrue) {
        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 strcasecmp(l->mName, r->mName) < 0;
        }

    
        if(S_ISDIR(l->mStat.st_mode))
            return TRUE;
        else
            return FALSE;
    }
    else {
        return strcasecmp(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(gSortMarkFileUp) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
    if(gSortDirUp == Qtrue) {
        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 strcasecmp(l->mName, r->mName) > 0;
            }

    
        if(S_ISDIR(r->mStat.st_mode)) return TRUE;
        return FALSE;
    }
    else {
        return strcasecmp(l->mName, r->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;

    if(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
     char* lext = extname(l->mName);
     char* rext = extname(r->mName);
    
     bool result;
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(l->mStat.st_mode)) {
              if(S_ISDIR(r->mStat.st_mode))
                    result = strcasecmp(l->mName, r->mName) < 0;
              else
                    result = TRUE;
         }
         else if(S_ISDIR(r->mStat.st_mode)) {
              result = FALSE;
         }
         else {
              const int cmp = strcasecmp(lext, rext);
              if(cmp == 0) {
                  result = strcasecmp(l->mName, r->mName) < 0;
              }
              else {
                  result = cmp < 0;
              }
         }
     }
     else {
         const int cmp = strcasecmp(lext, rext);
         if(cmp == 0) {
             result = strcasecmp(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;

    if(gSortMarkFileUp) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
     char* lext = extname(l->mName);
     char* rext = extname(r->mName);
    
     bool result;
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(r->mStat.st_mode)) {
            if(S_ISDIR(l->mStat.st_mode))
                result= strcasecmp(l->mName, r->mName) >0;
            else
                result = TRUE;
         }
         else if(S_ISDIR(l->mStat.st_mode)) {
              result = FALSE;
         }
         else {
              const int cmp = strcasecmp(lext, rext);
              if(cmp == 0) {
                  result = strcasecmp(l->mName, r->mName) > 0;
              }
              else {
                  result = cmp > 0;
              }
         }
     }
     else {
         const int cmp = strcmp(lext, rext);
         if(cmp == 0) {
             result = strcasecmp(l->mName, r->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;
     
    if(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) return strcasecmp(l->mName, r->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     const int lsize = S_ISDIR(l->mStat.st_mode) ? 0 : l->mLStat.st_size; 
     const int rsize = S_ISDIR(r->mStat.st_mode) ? 0 : r->mLStat.st_size;
    
     if(lsize == rsize) {
         return strcasecmp(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;

    if(gSortMarkFileUp) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) return strcasecmp(l->mName, r->mName) > 0;
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     const int lsize = S_ISDIR(l->mStat.st_mode) ? 0 : l->mLStat.st_size; 
     const int rsize = S_ISDIR(r->mStat.st_mode) ? 0 : r->mLStat.st_size;

     if(lsize == rsize) {
         return strcasecmp(l->mName, r->mName) > 0;
     }
     else {
         return lsize > rsize;
     }
}
    
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(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
                 if(cmp == 0) {
                     return strcasecmp(l->mName, r->mName) < 0;
                 }
                 else {
                    return cmp < 0;
                }
             }
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
     if(cmp == 0) {
         return strcasecmp(l->mName, r->mName) < 0;
     }
     else {
        return cmp < 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(gSortMarkFileUp) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
                 if(cmp == 0) {
                     return strcasecmp(l->mName, r->mName) > 0;
                 }
                 else {
                    return cmp > 0;
                 }
             }
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     double cmp = difftime(l->mLStat.st_mtime, r->mLStat.st_mtime);
     if(cmp == 0) {
         return strcasecmp(l->mName, r->mName) > 0;
     }
     else {
        return cmp > 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(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 if(l->mLStat.st_uid == r->mLStat.st_uid) {
                     return strcasecmp(l->mName, r->mName) < 0;
                 }
                 else {
                     return l->mLStat.st_uid < r->mLStat.st_uid;
                 }
             }
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     if(l->mLStat.st_uid == r->mLStat.st_uid) {
         return strcasecmp(l->mName, r->mName) < 0;
     }
     else {
         return l->mLStat.st_uid < r->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(gSortMarkFileUp) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 if(l->mLStat.st_uid == r->mLStat.st_uid) {
                     return strcasecmp(l->mName, r->mName) > 0;
                 }
                 else {
                    return l->mLStat.st_uid > r->mLStat.st_uid;
                 }
             }
//             if(S_ISDIR(l->mLStat.st_mode)) return strcasecmp(r->mName, l->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     if(l->mLStat.st_uid == r->mLStat.st_uid) {
         return strcasecmp(l->mName, r->mName) > 0;
     }
     else {
        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(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 if(l->mLStat.st_gid == r->mLStat.st_gid) {
                     return strcasecmp(l->mName, r->mName) < 0;
                 }
                 else {
                    return l->mLStat.st_gid < r->mLStat.st_gid;
                 }
             }
//             if(S_ISDIR(r->mLStat.st_mode)) return strcasecmp(l->mName, r->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     if(l->mLStat.st_gid == r->mLStat.st_gid) {
         return strcasecmp(l->mName, r->mName) < 0;
     }
     else {
        return l->mLStat.st_gid < r->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(gSortMarkFileUp) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 if(l->mLStat.st_gid == r->mLStat.st_gid) {
                     return strcasecmp(l->mName, r->mName) > 0;
                 }
                 else {
                    return l->mLStat.st_gid > r->mLStat.st_gid;
                 }
             }
//             if(S_ISDIR(l->mLStat.st_mode)) return strcasecmp(r->mName, l->mName) < 0;
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     if(l->mLStat.st_gid == r->mLStat.st_gid) {
         return strcasecmp(l->mName, r->mName) > 0;
     }
     else {
        return l->mLStat.st_gid > r->mLStat.st_gid;
     }
}

BOOL cDirWnd::sort_permission(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(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(l->mStat.st_mode)) {
             if(S_ISDIR(r->mStat.st_mode)) {
                 if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
                     return strcasecmp(l->mName, r->mName) < 0;
                 }
                 else {
                     return (l->mLStat.st_mode&S_ALLPERM) < (r->mLStat.st_mode&S_ALLPERM);
                 }
             }
             return TRUE;
         }
         if(S_ISDIR(r->mStat.st_mode)) return FALSE;
     }
     
     if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
         return strcasecmp(l->mName, r->mName) < 0;
     }
     else {
         return (l->mLStat.st_mode&S_ALLPERM) < (r->mLStat.st_mode&S_ALLPERM);
     }
}
    
BOOL cDirWnd::sort_permission_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(gSortMarkFileUp) {
        if(!l->mMark && r->mMark) {
            return TRUE;
        }
        if(l->mMark && !r->mMark) {
            return FALSE;
        }
    }
     if(gSortDirUp == Qtrue) {
         if(S_ISDIR(r->mStat.st_mode)) {
             if(S_ISDIR(l->mStat.st_mode)) {
                 if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
                     return strcasecmp(l->mName, r->mName) > 0;
                 }
                 else {
                     return (l->mLStat.st_mode&S_ALLPERM) > (r->mLStat.st_mode&S_ALLPERM);
                 }
             }
             return TRUE;
         }
         if(S_ISDIR(l->mStat.st_mode)) return FALSE;
     }
     
     if((l->mLStat.st_mode&S_ALLPERM) == (r->mLStat.st_mode&S_ALLPERM)) {
         return strcasecmp(l->mName, r->mName) > 0;
     }
     else {
         return (l->mLStat.st_mode&S_ALLPERM) > (r->mLStat.st_mode&S_ALLPERM);
     }
}

BOOL cDirWnd::sort_random(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(gSortMarkFileUp) {
        if(l->mMark && !r->mMark) {
            return TRUE;
        }
        if(!l->mMark && r->mMark) {
            return FALSE;
        }
    }

    if(gSortDirUp == Qtrue) {
        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 l->mSortRandom < r->mSortRandom;
        }

    
        if(S_ISDIR(l->mStat.st_mode))
            return TRUE;
        else
            return FALSE;
    }
    else {
        return l->mSortRandom < r->mSortRandom;
    }
}


void cDirWnd::Sort()
{
    gCurrentDir = this;

    if(mSortKind == kRandom) {
        for(int i=0; i<vector_size(mFiles); i++) {
            sFile* f = (sFile*)vector_item(mFiles, i);

            f->mSortRandom = random()%vector_size(mFiles);
        }

        vector_sort(mFiles, sort_random);
    }
    else {
        switch(mSortKind)
        {
        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;

        case kPermission:
            vector_sort(mFiles, sort_permission);
            break;

        case kPermissionReverse:
            vector_sort(mFiles, sort_permission_reverse);
            break;

        case kNone:
            read();
            break;
        }
    }
    
    hash_file_num_reset();
}

