//
// Copyright (C) 1999-2004 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <WScom.h>
#include <WSCdirTree.h>
#include <WSCclassInformation.h>
#include <WSCdevice.h>
#include <WSCblink.h>
#include <WSCcolorSet.h>
#include <WSCimageSet.h>
#include <WSDdev.h>
#include <WSDcolor.h>
#include <WSCfontSet.h>
#include <WSDappDev.h>
#include <WSCsform.h>
#include <WSDfileSystem.h>

WSMFguiClassInitialize(WSCdirTree, WSCtreeList);
WSMFversion(WSCdirTree, WSCtreeList);

#define WS_DT_OPEN 1
#define WS_DT_HAS_NO_SUB 2
#define WS_DT_HAS_SUB 4
#define WS_DT_SELECTED 8
#define WS_DT_FILE 16

//same one exists in WSClist.cpp...
#define SELECT_STATUS "ls-selected"

WSMFpropertyValueChange( WSCdirTree, WSNiconPixmap , short,WSGIappImageSet()->getImageNo("$(WSDIR)/sys/pixmaps/bi16.xpm"));
WSMFpropertyValueChange( WSCdirTree, WSNpixmapStyle , WSCuchar,WS_DYNAMIC_PIXMAP);
#define WS_DT_FILE_ICON_NAME "$(WSDIR)/sys/pixmaps/bi17.xpm"

WSCdirTree::WSCdirTree(WSCbase* base, char* objname):
			WSCtreeList(base, objname){

  _icon_pixmap = WSGIappImageSet()->getImageNo("$(WSDIR)/sys/pixmaps/bi16.xpm");
//  _virtual_scr = 0;
  _dir_name = WSGFstrdup("");
  _file_name = WSGFstrdup("");
  _mask_name = WSGFstrdup("");
  _select_dir = True;

  WSMFpropertyCreateStart
    WSMFparentCheckVerSrc(WSCdirTree);
    WSMFpropertyCreate(WSNdirName, char*, _dir_name,WSSdirName);
    WSMFpropertyCreate(WSNfileName,     char*, _file_name,WSSfileName  );
    WSMFpropertyCreate(WSNmaskFileName, char*, _mask_name,WSSmaskFileName );
    WSMFpropertyCreate(WSNselectDir, WSCbool, _select_dir,WSSselectDir );
      WSMFpropertySetSelection(WSRbool3,WSRbool3D);

    WSMFpropertyValueChangeDef( WSCdirTree,WSNiconPixmap ,short);
    WSMFpropertyValueChangeDef( WSCdirTree,WSNpixmapStyle ,WSCuchar);
    WSMFpropertyDelete(WSNdataSourceName);
    WSMFpropertyDelete(WSNdataSource);
    WSMFpropertyDelete(WSNdata);
  WSMFpropertyCreateEnd

}
WSMFproperty( WSCdirTree, WSNdirName,  char*, _dir_name,WSGFstrdup(""));
WSMFproperty( WSCdirTree, WSNselectDir, WSCbool, _select_dir, True);
WSMFproperty( WSCdirTree, WSNfileName, char*, _file_name, WSGFstrdup(""));
WSMFproperty( WSCdirTree, WSNmaskFileName, char*, _mask_name, WSGFstrdup(""))

void WSCdirTree::setWorkWSNdirName(char* dir){
  setSelectedDirName(dir);
}
void WSCdirTree::getWorkWSNdirName(char** dir){
  long pos = getSelectedPos();
  if (pos == -1){
    delete _dir_name;
    _dir_name = WSGFstrdup("");
    *dir = _dir_name;
    return;
  }
  WSCbase* item = getLabel(pos);
  WSCstring dirname;
  dirname = item->getProperty(WSNuserString);
  if (strcmp(_dir_name,(char*)dirname)){
    delete _dir_name;
    _dir_name = WSGFstrdup((char*)dirname);
  }
  *dir = _dir_name;
}
void WSCdirTree::setWorkWSNfileName(char* fname){
}
void WSCdirTree::getWorkWSNfileName(char** fname){
  long pos = getSelectedPos();
  if (pos == -1){
    delete _file_name;
    _file_name = WSGFstrdup("");
    *fname = _file_name;
    return;
  }
  WSCbase* item = getLabel(pos);
  WSCstring filename;
  filename = item->getProperty(WSNuserString);
  if (strcmp(_file_name,(char*)filename)){
    delete _file_name;
    _file_name = WSGFstrdup((char*)filename);
  }
  *fname = _file_name;
}
void WSCdirTree::setWorkWSNmaskFileName(char* data){}
void WSCdirTree::getWorkWSNmaskFileName(char** data){}
void WSCdirTree::setWorkWSNselectDir(WSCbool data){}
void WSCdirTree::getWorkWSNselectDir(WSCbool* data){}



long WSCdirTree::setSelectedDirName(char* dirname,WSCbool opened){
  if (dirname == NULL){
    return WS_ERR;
  }
#ifndef MSW
  if (dirname[0] != '/'){
    return WS_ERR;
  }
#endif  

  WSClistData dirlist;
  WSCstring tmp;
  tmp = dirname;
  long start = 1;
#ifdef MSW
  while( tmp.replaceString("\\\\","\\",0) );
  tmp.replaceString("\\","/",0);
  start = 0;
#endif
  while( tmp.replaceString("//","/",0) );

  WSCbase* item = getLabel(0);
  if ((long)item->getUserData(WS_LIST_TREE_OPEN) == 0){
    item->setUserData(WS_LIST_TREE_OPEN,(void*)1);
    item->setUserData(WS_LIST_TREE_OPEN_CH,(void*)1);
    _lb_adjust();
  }

  long i;
  long num =  tmp.getWords("/");
  long pre_pos = 0;
  for(i=start; i<num; i++){
    WSCstring lstr;
    lstr = tmp.getWord(i,"/");
    long j;
    long lnum = _lb_list.getNum();
    long fl = False;
    
    for(j=pre_pos; j<lnum; j++){
      WSCbase* item = getLabel(j);
//      if (item->getVisible() == False)
      if ((WSCbool)item->getProperty(WSNvis) == False){
        continue;
      }
      WSCstring istr;
      istr = item->getProperty(WSNlabelString);
//      if (!strcmp((char*)istr,(char*)lstr)){
      if (istr == lstr){
        fl = True;
        if (i == num -1){
          long dnum = _dir_inf.getNum();
          long k;
          for(k=0; k<dnum; k++){
            long val = (long)_dir_inf.getData(k);
            char* index = _dir_inf.getIndex(k);
            val &= ~WS_DT_SELECTED;
            _dir_inf.setData(index,(void*)val);
          }

          setSelectPos(j);
        }
        if (i == num -1 && opened == False){
        }else{
          if ((long)item->getUserData(WS_LIST_TREE_OPEN) == 0){
            item->setUserData(WS_LIST_TREE_OPEN,(void*)1);
            item->setUserData(WS_LIST_TREE_OPEN_CH,(void*)1);
            _lb_adjust();
          }
        }
        pre_pos = j;
        break;
      }
    }
    if (fl == False){
      _redraw_scr();
      return WS_ERR;
    }
  }
  _redraw_scr();
  return WS_NO_ERR;
}

char* WSCdirTree::getSelectedDirName(){
  long pos = getSelectedPos();
  if (pos == -1){
    delete _dir_name;
    _dir_name = WSGFstrdup("/");
    return _dir_name;
  }
  WSCbase* item = getLabel(pos);
  WSCstring dirname;
  dirname = item->getProperty(WSNuserString);
  if (strcmp(_dir_name,(char*)dirname)){
    delete _dir_name;
    _dir_name = WSGFstrdup((char*)dirname);
  }
  return _dir_name;
}


WSCdirTree::~WSCdirTree() {
  if (_dir_name != NULL){
    delete _dir_name;
  }
}
void WSCdirTree::reset(){
  _dir_inf.clear();  
  long pos = _adjust_dir("","",0,0,True);
  long num = _lb_list.getNum();
//printf("WSCdirTree::_lb_adjust pos=%d num=%d\n",pos,num);
  long i;
  for(i=pos; i<num; i++){
//printf("WSCdirTree::_lb_adjust del=%d\n",i);
    delPos(pos);
  } 
}
void WSCdirTree::_adjust(){
  int num = _lb_list.getNum();
//  int i;
  if (num == 0){
    _lb_adjust();
  }
  WSClist::_adjust();
}
void WSCdirTree::_lb_adjust(){
  int num = _lb_list.getNum();
  int i;
  long update = 0;
  long update_pos = 0;
  if (num == 0){
    update = 1;
  }
  for(i=0; i<num; i++){
//printf("WSCdirTree::_lb_adjust for1 %d...\n",i);
    WSCbase* item = getLabel(i);
    if ((long)item->getUserData(WS_LIST_TREE_OPEN_CH) != 0){
      update = 1;
      update_pos = i;
      break;
    }
  }
  if (update != 0){ 
//    _dir_inf.clear();
    long selected_pos = getSelectedPos();
    for(i=0; i<num; i++){
      WSCbase* item = getLabel(i);
//printf("WSCdirTree::_lb_adjust for2 %d...\n",i);
//      if (item->getVisible() != False){
        WSCstring dir;
        dir = item->getProperty(WSNuserString);
        long open = (long)item->getUserData(WS_LIST_TREE_OPEN);
        long dstatus = 0; 
        if (open == False){
        }else{
          dstatus |= WS_DT_OPEN;
        }
        if (item->getVisible() != False){
          if (selected_pos == i){
            dstatus |= WS_DT_SELECTED;
          }
          _dir_inf.setData((char*)dir,(void*)dstatus);
        }
        item->setPropertyV(WSNselectColor,(short)0);
        item->setPropertyV(WSNselectForeColor,(short)0);
        item->setUserData(SELECT_STATUS,(void*)0);
//      }
    }
//    for(i=0; i<num; i++){
//      WSCbase* item = getLabel(i);
//      item->setVisible(False); 
//    } 
    long pos = 0;
    if (update_pos == 0){
      pos = _adjust_dir("","",0,0,True);
      long num = _lb_list.getNum();
//printf("WSCdirTree::_lb_adjust pos=%d num=%d\n",pos,num);
      for(i=pos; i<num; i++){
//printf("WSCdirTree::_lb_adjust del=%d\n",i);
        delPos(pos);
      } 
    }else{
      WSCbase* item = getLabel(update_pos);
      WSCstring path = item->getProperty(WSNuserString);
      WSCstring dname = WSGFgetDirName(path);
      WSCstring fname = WSGFgetFileName(path);
      if (!strcmp((char*)dname,".")){
        dname = "/";
#ifdef MSW
        fname = path;
#endif
      }
      long level = (long)item->getUserData(WS_LIST_INDENT_LEVEL);
      pos = _adjust_dir(dname,fname,level,update_pos,True,False);
    }
  }
  WSClist::_lb_adjust();
//printf("WSCdirTree::_lb_adjust here\n");
}

long WSCdirTree::_adjust_dir(char* path,char* subdir,long level,long pos,long diropen,WSCbool all_update){
//printf("WSCdirTree::_adjust_dir(%s,%s,%d,%d,%d)\n",path,subdir,level,pos,diropen);
  if (pos * _lb_height > 32768){
    return pos;
  }
  long lnum = _lb_list.getNum();
  if (pos < lnum){
    WSCbase* item = getLabel(pos);
    if (all_update == False &&
        (long)item->getUserData(WS_LIST_INDENT_LEVEL) < level){
      if (subdir[0] == 0){
#ifdef MSW
        addItem("My computer",pos);
#else
        addItem("/",pos);
#endif
      }else{
        addItem(subdir,pos);
      }
    }else{
      if (subdir[0] == 0){
#ifdef MSW
        item->setProperty(WSNlabelString,"My computer");
#else
        item->setProperty(WSNlabelString,"/");
#endif
      }else{
        item->setProperty(WSNlabelString,subdir);
      }
    }
  }else{
    if (subdir[0] == 0){
#ifdef MSW
      addItem("My computer");
#else
      addItem("/");
#endif
    }else{
      addItem(subdir);
    }
  }

  setItemValue(pos,WS_INDENT_LEVEL,level);
  setItemValue(pos,WS_ICON,(int)WSGIappImageSet()->getImageName(_icon_pixmap));

  WSCbase* item = getLabel(pos);
  if (subdir[0] == 0){
    item->setProperty(WSNuserString,"/");
  }else{
    WSCstring path2;
    if (path[0] == '/' && path[1] == 0){
#ifdef MSW
      path2 << subdir;
#else
      path2 << "/" << subdir;
#endif
    }else{
      path2 << path << "/" << subdir;
    }
    item->setProperty(WSNuserString,(char*)path2);
  }
  
  pos++;
  if ( diropen != False){
    WSClistData* dir_list = NULL;
    WSClistData* file_list = NULL;
    long dstatus;
    if (subdir[0] == 0){
      dstatus = (long)_dir_inf["/"];
#ifdef MSW
      dir_list = WSGIappFileSystem()->showDir("");
#else
      dir_list = WSGIappFileSystem()->showDir("/");
#endif
      if (_select_dir == False){
#ifdef MSW
      file_list = WSGIappFileSystem()->showFile("");
#else
      file_list = WSGIappFileSystem()->showFile("/");
#endif
      }
      dstatus &= ~WS_DT_FILE;
      _dir_inf.setData((char*)"/",(void*)dstatus);

    }else{
      WSCstring path2;
      if (path[0] == '/' && path[1] == 0){
#ifdef MSW
        path2 << subdir;
        dstatus = (long)_dir_inf[(char*)path2];
        if (dstatus & WS_DT_OPEN){
          dir_list = WSGIappFileSystem()->showDir((char*)path2);
          if (_select_dir == False){
             file_list = WSGIappFileSystem()->showFile((char*)path2);
          }
        }else{
          dir_list = new WSClistData();
          dir_list->add((void*)WSGFstrdup("dir-t"));
        }
#else
        path2 << "/" << subdir;
        dstatus = (long)_dir_inf[(char*)path2];
        dir_list = WSGIappFileSystem()->showDir((char*)path2);
        if (_select_dir == False){
           file_list = WSGIappFileSystem()->showFile((char*)path2);
        }
#endif
        dstatus &= ~WS_DT_FILE;
        _dir_inf.setData((char*)path2,(void*)dstatus);
      }else{
        path2 << path << "/" << subdir;
        dstatus = (long)_dir_inf[(char*)path2];
        dir_list = WSGIappFileSystem()->showDir((char*)path2);
        if (_select_dir == False){
           file_list = WSGIappFileSystem()->showFile((char*)path2);
        }
        dstatus &= ~WS_DT_FILE;
        _dir_inf.setData((char*)path2,(void*)dstatus);
      }
//printf("dir=%s status=0x%x\n",(char*)path2,dstatus);
    }

    if (dir_list == NULL && _select_dir != False){
      return pos;
    }
    long no_exec = 0; 

    if (dir_list != NULL){
      long num = dir_list->getNum();
//printf("dir_list num=%d\n",num);
      if (num > 0){
        int i;
        WSCstring path2;
        if (path[0] == '/' && path[1] == 0){
#ifdef MSW
          path2 << subdir;
#else
          path2 << "/" << subdir;
#endif
        }else{
          path2 << path << "/" << subdir;
        }
        if (dstatus & WS_DT_OPEN){
          item->setUserData(WS_LIST_TREE_OPEN,(void*)1);
        }else{
          item->setUserData(WS_LIST_TREE_OPEN,(void*)0);
        }
        if (dstatus & WS_DT_SELECTED){
          item->setPropertyV(WSNselectColor,(short)_select_color);
          item->setPropertyV(WSNselectForeColor,(short)_select_fore_color);
          item->setUserData(SELECT_STATUS,(void*)1);
        }
        for(i=0; i<num; i++){
//printf("WSCdirTree::_adjust_dir child for2 %d...\n",i);
          long pos2;
          char* childdir = (char*)dir_list->getData(i);
          if (no_exec != 0){
            delete childdir;
            continue;
          }
          if (dstatus & WS_DT_OPEN){
            pos2 = _adjust_dir((char*)path2,childdir,level+1,pos,True,all_update);
          }else{
            pos2 = _adjust_dir((char*)path2,childdir,level+1,pos,False,all_update);
            no_exec = 1;
          }
          pos = pos2;
          delete childdir;
        }
      }
      delete dir_list;
    }

    if (file_list != NULL){
      long num = file_list->getNum();
      if (no_exec != 0){
        int i;
        for(i=0; i<num; i++){
          char* fname = (char*)file_list->getData(i);
          delete fname;
        }
        delete file_list;
        return pos;
      }
      if (num > 0){
        int i;
        for(i=0; i<num; i++){
          char* fname = (char*)file_list->getData(i);
          if (no_exec != 0){
            delete fname;
            continue;
          }
          WSCstring tmp(fname);
          long sufixw = tmp.getWords(".");
          if (_mask_name != NULL && _mask_name[0] != 0 && sufixw < 2){
            delete fname;
            continue;
          }
          WSCstring sufix = tmp.getWord(sufixw -1,".");
          if (_mask_name != NULL && _mask_name[0] != 0 &&
              strcmp(sufix.getString(),_mask_name)){
            delete fname;
            continue;
          }
          if (dstatus & WS_DT_OPEN){
          }else{
            no_exec = 1;
          }
          WSCstring path2;
          if (path[0] == '/' && path[1] == 0){
#ifdef MSW
            path2 << subdir << "/" << fname;
#else
            path2 << "/" << subdir << "/" << fname;
#endif
          }else{
            path2 << path << "/" << subdir << "/" << fname;
          }

          long lnum = _lb_list.getNum();
          if (pos < lnum){
            WSCbase* item = getLabel(pos);
            if (all_update == False &&
                (long)item->getUserData(WS_LIST_INDENT_LEVEL) < level+1){
              addItem(fname,pos);
              WSCbase* item = getLabel(pos);
              if (item != NULL){
                item->setProperty(WSNuserString,(char*)path2);
              }
            }else{
              item->setProperty(WSNlabelString,fname);
              item->setProperty(WSNuserString,(char*)path2);
            }
          }else{
            addItem(fname);
            WSCbase* item = getLabel(pos);
            if (item != NULL){
              item->setProperty(WSNuserString,(char*)path2);
            }
          }
          setItemValue(pos,WS_INDENT_LEVEL,level+1);
          setItemValue(pos,WS_ICON,(int)WS_DT_FILE_ICON_NAME);

          long fstatus = (long)_dir_inf[(char*)fname];
          fstatus |= WS_DT_FILE;
          _dir_inf.setData((char*)fname,(void*)fstatus);
          if (fstatus & WS_DT_SELECTED){
            WSCbase* item = getLabel(pos);
            if (item != NULL){
              item->setPropertyV(WSNselectColor,(short)_select_color);
              item->setPropertyV(WSNselectForeColor,(short)_select_fore_color);
              item->setUserData(SELECT_STATUS,(void*)1);
            }
          }

          pos++;
          delete fname;
        }
      }
      delete file_list;
    }
    while(1){
      WSCbase* item = getLabel(pos);
      if (item != NULL){
        long lev1 = (long)item->getUserData(WS_LIST_INDENT_LEVEL);
        if (level < lev1){
          WSCvariant fname = item->getProperty(WSNlabelString);
//printf("!!!!! pos=%d level=%d lev1=%d #%s# open=%d\n",pos,level,lev1,(char*)fname,diropen);
          delPos(pos);
          continue;
        }
        break;
      }
      break;
    }
  }
  return pos;
}

WSCstring WSCdirTree::getDirInf(){
  WSCstring ret;
//  long num = _dir_inf.getNum();
  long num = _lb_list.getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbase* item = getLabel(i);
    long vis = (long)item->getProperty(WSNvis);
    long level = (long)item->getUserData(WS_LIST_INDENT_LEVEL);
    long selected = (long)item->getUserData(SELECT_STATUS);
    WSCvariant path = item->getProperty(WSNuserString);
    WSCvariant fname = item->getProperty(WSNlabelString);
    WSCvariant iname = item->getProperty(WSNlabelPixmap);
    long val = (long)_dir_inf[(char*)path];
    if (i!=0){
      ret << "\n";
    }
    WSCstring tmp;
    tmp << path << "," << fname << "," << iname << ","
        << val << "," << level << "," << selected << "," << vis;
    ret << tmp;
  }
  return ret;
}

void WSCdirTree::setDirInf(WSCstring inf){
  long num = inf.getWords("\n");
  long i;
  long select_pos = 0;
  for(i=0; i<num; i++){
    WSCstring line = inf.getWord(i,"\n");
    WSCstring path = line.getWord(0,",");
    WSCstring fname = line.getWord(1,",");
    WSCstring iname = line.getWord(2,",");
    long val = atoi(line.getWord(3,","));
    long level = atoi(line.getWord(4,","));
    long selected = atoi(line.getWord(5,","));
    long vis = atoi(line.getWord(6,","));
    if (selected != 0){
      select_pos = i;
    }
    WSCbase* item = getLabel(i);
    if (item == NULL){
      addItem(fname);
      item = getLabel(i);
      if (item == NULL){
        return;
      }
    }else{
      item->setProperty(WSNlabelString,fname);
    }
    item->setProperty(WSNuserString,path);
    item->setProperty(WSNlabelPixmap,iname);
    item->setUserData(WS_LIST_INDENT_LEVEL,(void*)level);
    _dir_inf.setData((char*)path,(void*)val);
    if (val & WS_DT_OPEN ){
      item->setUserData(WS_LIST_TREE_OPEN,(void*)1);
    }else{
      item->setUserData(WS_LIST_TREE_OPEN,(void*)0);
    }
    if (vis != False){
      item->setVisible(True);
    }else{
      item->setVisible(False);
    }
  }
  setSelectPos(select_pos);
  updateList();
}


