/* nmcopyopdir.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2014 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "nmcopyopdir.hh"
#include "copyopwin.hh"
#include "deleteop.h"
#include "simplelist.hh"
#include "verzeichnis.hh"
#include "fileentry.hh"
#include "copyorder.hh"
#include "deleteorder.hh"

NM_CopyOp_Dir::NM_CopyOp_Dir(const FileEntry *fe)
{
  int erg;

  fileentry=fe;
  subdirs=new List();
  verz=new Verzeichnis();
  files=dirs=error_counter=0;
  bytes = 0;
  ok=false;
  user_abort = false;
  
  erg = verz->readDir( fe->fullname );
  if ( erg == 0 ) ok = true;
  else if ( erg > 0 ) user_abort = true;
}

NM_CopyOp_Dir::~NM_CopyOp_Dir()
{
  int id=subdirs->initEnum();
  NM_CopyOp_Dir *cod=(NM_CopyOp_Dir*)subdirs->getFirstElement(id);
  while(cod!=NULL) {
    delete cod;
    cod=(NM_CopyOp_Dir*)subdirs->getNextElement(id);
  }
  subdirs->closeEnum( id );
  delete subdirs;
  delete verz;
}

int
NM_CopyOp_Dir::createSubDirs( std::shared_ptr< struct copyorder > co,unsigned long *gf,unsigned long *gd)
{
  NM_CopyOp_Dir *cod1;
  bool enter;
  bool cancel=false;
  
  /*TODO: vielleicht sollte der Fehler weitergereicht werden, aber cancel=true soll nicht entstehen
    daher erstmal 0 zurueckgeben */
  if(ok==false) return 0;

  if ( verz->dirOpened() == false ) return 0;

/*TODO:Vorerst zu langsam, kann aber an MemSystem liegen, daher nochmal ohne
       das pruefen
  if(co->cowin!=NULL) {
    co->cowin->setmessage(verz->getDir(),1);
    if ( co->cowin->redraw() != 0 ) cancel = true;
  }*/

  for ( Verzeichnis::verz_it fe_it1 = verz->begin();
        fe_it1 != verz->end() && cancel == false;
        fe_it1++ ) {
    FileEntry *fe = *fe_it1;
    if(strcmp(fe->name,"..")!=0) {
      enter=false;
      if(fe->isDir()==true) {
        // fe is a dir, check if it is a link and take it only when follow_symlinks==true
	// entry is a dir so it cannot be a corrupt link so no need to check
        if(fe->isLink==false) enter=true;
        else if(co->follow_symlinks==true) enter=true;
      }
      if(enter==true) {
        // fe is a dir so creating corresponding entry
        cod1=new NM_CopyOp_Dir(fe);
        if ( cod1->user_abort == false ) {
          // recursive call
          if(cod1->createSubDirs(co,gf,gd)!=0) cancel=true;
        } else cancel = true;
        // add the values from this subdir to this dir
        files+=cod1->files;
        dirs+=cod1->dirs;
        bytes+=cod1->bytes;

        // add this subdir to the list
        subdirs->addElement(cod1);
        
        // this is a dir so inc the counter
        dirs++;
        (*gd)++;

        if(co->cowin!=NULL) {
          co->cowin->set_files_to_copy(*gf);
          co->cowin->set_dirs_to_copy(*gd);
          if ( co->cowin->redraw() & 1 ) cancel = true;
        }
      } else {
        // is not dir (mostly a file but can also be links ...)
        files++;
        (*gf)++;
        if ( ( fe->isLink == true ) &&
             ( co->follow_symlinks == true ) &&
             ( fe->isCorrupt == false ) ) {
	  bytes += fe->dsize();
        } else {
          bytes += fe->size();
        }
      }
    }
  }
  return (cancel==true)?1:0;
}

int
NM_CopyOp_Dir::createSubDirs(struct deleteorder *delorder,unsigned long *gf,unsigned long *gd)
{
  NM_CopyOp_Dir *cod1;
  bool enter;
  bool cancel=false;
  
  if(ok==false) return 0;

  if ( verz->dirOpened() == false ) return 0;

  for ( Verzeichnis::verz_it fe_it1 = verz->begin();
        fe_it1 != verz->end() && cancel == false;
        fe_it1++ ) {
    FileEntry *fe = *fe_it1;
    if(strcmp(fe->name,"..")!=0) {
      enter=false;
      if(fe->isDir()==true) {
        // fe is a dir, check if it is a link and take it only when follow_symlinks==true
        if(fe->isLink==false) enter=true;
      }
      if(enter==true) {
        // fe is a dir so creating corresponding entry
        cod1=new NM_CopyOp_Dir(fe);
        if ( cod1->user_abort == false ) {
          // recursive call
          if(cod1->createSubDirs(delorder,gf,gd)!=0) cancel=true;
        } else cancel = true;
        // add the values from this subdir to this dir
        files+=cod1->files;
        dirs+=cod1->dirs;
        bytes+=cod1->bytes;
        
        // add this subdir to the list
        subdirs->addElement(cod1);
        
        // this is a dir so inc the counter
        dirs++;
        (*gd)++;

        if(delorder->dowin!=NULL) {
          delorder->dowin->set_files_to_delete(*gf);
          delorder->dowin->set_dirs_to_delete(*gd);
          if(delorder->dowin->redraw()!=0) cancel=true;
        }
      } else {
        // is not dir (mostly a file but can also be links ...)
        files++;
        (*gf)++;
        // when deleting only size of file, not the dest matters
        bytes += fe->size();
      }
    }
  }
  return (cancel==true)?1:0;
}
