/*
    Explorer
    (c) 2012-2020 Denis Sureau
    Explorer.js is a node module for file management.
    Licence: LGPL 3.0
    Use it freely but do not change this copyright notice.
*/

const os = require('os');
const path = require('path');
const url = require('url');
const fs = require('fs');
const { BrowserWindow, ipcMain } = require('electron')
const MarkdownIt = require('markdown-it')

const print = console.log;
var event;

var TEMPORARY = '/temp/';
var currpath = [];

var rootdir = "";

exports.setRoot = function(rpath) {
  rootdir = rpath
} 

exports.getRoot = function() {
  return rootdir
} 

function sendToInterface(a) {
    event.sender.send("interface", JSON.stringify(a));
}

function messageToInterface(content)
{
   event.sender.send("interface", JSON.stringify( {
    "type":"message",  
    "content" : content 
  }));
}

exports.path = function (target) { 
  return currpath[target]; 
}

exports.ostitle = '';

exports.loadIni = function (inipath)
{
    var platform = os.platform();
    console.log("Setup for OS "+ platform)
    var oslist = {
        'win32'  : '[Windows]',
        'linux'  : '[Linux]',
        'freebsd': '[Linux]',
        'darwin' : '[Mac]'
    }
    ostitle = oslist[platform];
  
	var data = fs.readFileSync(inipath, 'utf8');
	var lines = data.split(/\r\n|\r|\n/);
  var openos = false;

	for(var i = 0; i < lines.length; i++)
	{
    line = lines[i];
    if(line.length < 1) continue;
    if(line.charAt(0) == ';') continue;
		if(line.charAt(0) == '#') continue;
    if(line.charAt(0) == '[') {
        openos = false;
        if(ostitle==line)  openos = true;   
        continue;     
    }
    if(openos) {
        var kval = line.split(/\=/);
        if(kval.length < 2) continue;
        var k = kval[0].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        var v = kval[1].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        config[k] = v.replace(/^"(.*)"$/, '$1');
      }
    }
    return platform;
}


function buildDate(atime)
{
  var day = atime.getDate();
  if(day < 10) day = '0' + day;
  var month = atime.getMonth() + 1;
  if(month < 10) month = '0' + month;
  var hour = atime.getHours();
  if(hour < 10) hour = '0' + hour;
  var minute = atime.getMinutes();
  if(minute < 10) minute = '0' + minute;
  return( day + '/' + month + '/' + atime.getFullYear() + ' ' + hour + ':' + minute );
}

function noHTMLchars(s){
    s = s.replace(/&lt;/g, '<');
    s = s.replace(/&gt;/g, '>');
    s = s.replace(/&quot;/g, '"');
    s = s.replace(/&copy;/g, '©');
    return s.replace(/&amp;/g, '&');
}

function canonicalPath(s){
    s = s.replace(/\\\\/g, '/');    
    return s.replace(/\\/g, '/');
}  

function getdir(params)
{
  var thepath = currpath[params.target];
  print("Getdir currentpath request: " + thepath);

  var event = params.event

  thepath = thepath.replace(/\\/gi, "/");
  thepath = thepath.replace(/\/\//gi, "/");

  var sumsize = 0;
  var sumfile = 0;

  var result = fs.existsSync(thepath);
  if(!result) {
     messageToInterface("Dir not found " + thepath);
     return;
  }

  fs.readdir(thepath, function(err, arrfiles)   {
	var dirlist = [];
    if(thepath != "/")  {
     	if((thepath.length > 3) || (thepath.length < 2) || (thepath.substr(1,2) != ':/')) {
         	dirlist.push([ 'dir', '..']);
        }
    }
    if(arrfiles===undefined) return;  
		for(var i = 0; i < arrfiles.length; i++) {
			var name = arrfiles[i];
      if(name[0] == ".") continue;
			var p = path.join(thepath , name);
            try
            {
			     var fdesc = fs.statSync(p);
                if (fdesc && fdesc.isDirectory())  {
                    dirlist.push( [ 'dir', name ] );
                }
                else
                {
                    var thedate = buildDate(fdesc.mtime);
                    dirlist.push( [ 'file', name, fdesc.size, thedate ] );
                    sumsize += fdesc.size;
                    sumfile ++;
                }
            }
            catch(e)  { 
                console.log("Enable to read " + p);   
            }
	   }

      fs.realpath(thepath, "", function (err, resolvedPath) {
          if (err) throw err;
          print("Explorer getdir resolvedPath: " + resolvedPath);
          currpath[params.target]= resolvedPath;
          var data = JSON.stringify({
            "type": "dirdata", 
            'path': resolvedPath,
            'list' : dirlist,
            'target' : params.target,
            'iszip' : false,
            'drag' : params.drag
          } )
          event.sender.send("filelist", data)
      
          var info = JSON.stringify({
            "type":"stats",
            "target": params.target,
            "files" : sumfile,
            "dirs"  : dirlist.length - sumfile,
            "size" : sumsize
         });

        event.sender.send("stats", info)  
     
	}); // realPath
 });  // readdir
}

exports.readImage = readImage;

function setpath(filepath, target)
{
  currpath[target] = filepath;
  //console.log("setpath now " + currpath[target] + " " + target);
  return true;
}

function dirup(target) {
  var p = currpath[target];
  p = p.replace(/\\/gi, "/");
  p = p.replace(/\/\//gi, "/");
  if(p.length > 1 && p.slice(-1) == "/") p = p.slice(0, -1);
  var x = p.lastIndexOf("/");
  currpath[target] = p.slice(0, x + 1);
  return true;
}

function subdir(sd, target) {
    var p = currpath[target];
    if(sd == '.') return;
    if(sd[0] == "/" || sd[1] == ':')  {
      p = sd;
    }  
    else  {
        if(p == undefined) {
            p = rootdir;
        }  
        p = path.join(p, sd);
    }
    currpath[target] = p;
}

function chdir(filepath, target) {
    if(filepath.slice(-2) == "..") return dirup(target);
    if(filepath.charAt(0) == "/")  {
        return setpath(filepath, target);
    }
    if(filepath.length > 2 && filepath.charAt(1) == ':')  {
        currpath[target] = filepath;
        return true;
    }
    subdir(filepath, target);
    return true;
}

function godir(filepath, target) {
  filepath = filepath.replace(/\\/gi, "/");
  filepath = filepath.replace(/\/\//gi, "/");
  var result = fs.existsSync(filepath);
  
  if(!result) {
     sendToInterface( {
        "type":"confirm",
        "question" : filepath + " does not exists. Create?",
        "command": "createdir",
        "path" : filepath,
        "tpath": target
     });
     return;
  }  
  currpath[target] = filepath;
}


function normalize(thepath, target) {
  thepath = path.join(currpath[target], thepath);
  thepath = thepath.replace(/\\/gi, "/");
  thepath = thepath.replace(/\/\//gi, "/");
  return thepath;
}

function fillBox(params)
{
  var target = params.target;
  var boxpath = params.path;
  boxpath = path.join(process.resourcesPath, boxpath)
  var result = fs.existsSync(boxpath);
  if(!result) {
      messageToInterface("Dir not found " + boxpath);
      return;
  }
  
  var dirlist = [];
  var content = "";
  var arrFiles = fs.readdirSync(boxpath);
  if(arrFiles != undefined && arrFiles.length > 1)
  {
		for(var i = 0; i < arrFiles.length; i++)
		{
            var name = arrFiles[i]; 
            var p = path.join(boxpath, name);
            try
            {
			    var fdesc = fs.statSync(p);
                if (fdesc != undefined && fdesc.isDirectory()) {
                    dirlist.push(name);
                }  
            }
            catch(e)  { }
	       }
    }

	event.sender.send("box", JSON.stringify({
       'action': 'fillbox', 
       'path': boxpath,
       'target': target,
       'list': dirlist
  } ));  
}

function loadBoxApp(params)
{
  sendToInterface({'type': 'boxapp', 'path': params.path,'target': params.target });  
}

function readImage(filepath)
{
    var ext = path.extname(filepath);
    console.log("Launching request for image: " + filepath);
    fs.exists(filepath, function(result) {
    	fs.readFile(filepath, function(err, file) {
            console.log("Request for image completed.");
            sendToInterface({
                "type":"image", 
                "ext": ext, 
                "path": filepath
                ,"content" : new Buffer(file).toString('base64')
            });
            return file;
        }
      );
    });
}

function rename(params)
{
  var target = params.target;
  var oldname = path.join(currpath[target], params.oldname);
  oldname=noHTMLchars(oldname);
  var newname = path.join(currpath[target], params.newname);
  try {
    fs.renameSync(oldname, newname);
  }
  catch(e) {
     messageToInterface("Enable to rename " + oldname + " to " + newname + " " + e);
  }
}

var errorcount = 0;
function deletesub(basepath) {
  try {
    var flist = fs.readdirSync(basepath);
  }
  catch(e) { return; }

  if(flist.length > 0) {
    for (var i = 0; i < flist.length; i++)  {
      var fullpath = path.join(basepath, flist[i]);
      if (fs.statSync(fullpath).isDirectory())
        deletesub(fullpath);
      else  {
        try {
          if(fs.unlinkSync(fullpath))
            errorcount++;
          else
            totalsize++;
        }
        catch(e) {
          errorcount++;
        }
      }
    }
  }
  fs.rmdirSync(basepath);
};

function deletelist(params) {
    var target = params.target;
    var flist = params.list;
    totalfile = 0;
    errorcount = 0;

    for(var i = 0; i < flist.length;i++)  {
        if(flist[i]=='') continue;
        var p = path.join(fpath, flist[i]);

        var stats = fs.statSync(p);
        if(stats.isDirectory()) {
            deletesub(p);
        }
        else {
        if(fs.unlinkSync(p))
            errorcount++;
        else
            totalsize++;
        }
    }

    var message =  totalsize + " deleted";
    if(errorcount) message += ", " + errorcount + " not deleted";
    message += '.';

    console.log("Deleted");
    sendToInterface({"type":'status','content':message });
}

function deleteEntry(params) {
    var target = params.target;
    var fpath = params.path;
    var flist = params.list;
    totalfile = 0;
    errorcount = 0;
    
    if(fpath.substr(-1) == "/" && fpath.substr(-1) == "\\") {
        fpath += flist[0]
    }

    var stats = fs.statSync(fpath);
    if(stats.isDirectory()) {
        var message = fpath + " is a directory, not deleted."
        sendToInterface({"type":'status','content': message });  
        return
    }
    else {
        if(fs.unlinkSync(fpath)) {
            errorcount++;
        }
        else {
            totalsize++;
        }
    }

    var message =  totalsize + " deleted";
    if(errorcount) message += ", " + errorcount + " not deleted";
    message += '.';

    console.log(fpath + " deleted");
    sendToInterface({"type":'status','content':message });
}


function copySync(sourcepath, targetpath)
{
  var buffer = new Buffer(65536);
  var readHandle = fs.openSync(sourcepath, 'r');
  var writeHandle = fs.openSync(targetpath, 'w');
  var size;
  var seekoffset = 0;
  try {
    do
    {
      size = fs.readSync(readHandle, buffer, 0, 65536, seekoffset);
      if(size > 0)
        fs.writeSync(writeHandle, buffer, 0, size);
      seekoffset += size;
    }
    while (size > 0);
  } catch(e) {
     console.log("Error, enable to copy " + sourcepath + ", " + e.message);
  }

  fs.closeSync(readHandle);
  fs.closeSync(writeHandle);
  return;
}

function copyIf(sourcepath, targetpath, promptdup)
{
  if(promptdup)
  {
    if(fs.existsSync(targetpath))
    {
      console.log(targetpath + " already exists...");
      sendToInterface({
        "type":"confirm",
        "question" : targetpath + " already exists. Overwrite?",
        "command": "copyover",
        "path" : sourcepath,
        "tpath" : targetpath, 
      });
      return;
    }
  }
  copySync(sourcepath, targetpath);
  return;
};


function copysub(flist, source, target)
{
  for(var i = 0; i < flist.length; i++)
  {
    var nextfile = flist[i];
    if(nextfile=='') continue;
    var sourcepath = path.join(source, nextfile);
    var targetpath = path.join(target, nextfile);
    
    sourcepath = noHTMLchars(sourcepath);
    
    var info = "Copying "+ sourcepath + " to " + target;
    console.log(info);
    sendToInterface({"type":"status", "content": info });
      
    var stats = fs.statSync(sourcepath);
    if(stats.isDirectory())
    {
      if(!fs.existsSync(targetpath))
        fs.mkdirSync(targetpath);
      var sublist = fs.readdirSync(sourcepath);
      copysub(sublist, sourcepath, targetpath);
    }
    else if(stats.isFile())
    {
      copyIf(sourcepath, targetpath, true);
    }
  }

}

function filecopy(params)
{
    var selection = params.list;
    if(selection.length == 0)  {
        console.log("No file to copy.")
        return;
    }
    var source = currpath[params.source];
    var target = currpath[params.target];
    copysub(selection, source, target);

    var s = ""; 
    if(selection.length > 1) s = "s";
    sendToInterface({"type":"status", "content": selection.length + ' file' + s + ' copied.' });

    console.log(selection.length + " files copied.");
}


function synchrosub(flist, source, target, recurse, copyAll, total)
{
  if(flist.length == 0)
  {
    flist = fs.readdirSync(source);
    if(flist.length==0) return;
  }

  for(var i = 0; i < flist.length; i++)
  {
    var nextfile = flist[i];
    if(nextfile=='') continue;
    var sourcepath = path.join(source, nextfile);
    var targetpath = path.join(target, nextfile);
    sourcepath = noHTMLchars(sourcepath);
    
    var stats = fs.statSync(sourcepath);
    if(stats.isDirectory())
    {
      if(!recurse) continue;
      if(!fs.existsSync(targetpath))  {
        if(!copyAll) continue;      
        fs.mkdirSync(targetpath);
      }  
      var sublist = fs.readdirSync(sourcepath);
      synchrosub(sublist, sourcepath, targetpath, true, copyAll, total);
    }
    else 
    if(stats.isFile())
    {
      var newer = copyAll;
      if(fs.existsSync(targetpath)) {
          var tstat = fs.statSync(targetpath); 
          if(stats.mtime.getTime() > tstat.mtime.getTime()) newer = true;
      }
      if(newer) {
        var info = "Copying "+ sourcepath + " to " + target;
        console.log(info);
        sendToInterface({ "type":"status", "content": info });
        copySync(sourcepath, targetpath);
        total++;
      }  
    }
  }
  return total;
}

function synchronize(params)
{
  var source = currpath[params.source];
  var target = currpath[params.target];

  var selection = params.list;
  console.log("Synchronizing from " + source + " to "+ target);
  var total = synchrosub(selection, source, target, params.recursive, params.copyall, 0);

  var s = ""; 
  if(total > 1) s = "s";

  sendToInterface({ "type":"status",  "content": total+' file'+s+' copied or updated.' });
  console.log(total + " files copied or updated.");
}

/* Read the content of a file, send it to the editor */

function getContent(params) {
	var fullpath = params.path;
	var here = fs.existsSync(fullpath);
	if(!here) {
	    print("File '" + fullpath + "' not found...");
        if(params.project != null) {
            console.log("Loading project anyway...");
            sendToInterface({
              "type":"openPrj", 
              'project':params.project
            });
        }
      print("Loading canceled...")
	    return;
	}    

  var stats = fs.statSync(fullpath);
  if(stats.isDirectory())  {
	  messageToInterface("Can't edit " + fullpath + ", it is a directory.");
	  return;
  }
  var data = new String(fs.readFileSync(fullpath));
  var ext = path.extname(fullpath);
  var a = {
        "type":"openDoc", 
        'ext': ext.substr(1),
        'content': data, 
        'filename': fullpath,
        'project' : params.project 
    }
  sendToInterface(a);
  print("Data sent...");
  sendToInterface({"type":'status', 'content' : fullpath });
}


function openProject(params)
{
    var fullpath = canonicalPath(params.name);
    if(fullpath == '') return;
	  var here = fs.existsSync(fullpath);
	  if(!here) {
	    print("Project file '" + fullpath + "' not found...");
      if(params.mode == true) {
            var a = {
                "type":"confirm",
                "question" :"Project file '" +fullpath+ "' not found. Remove from list?",
                "command": "delprj",
                "path" : fullpath
            }
            sendToInterface(a)
        }    
	   return;
	  }    
    var data = new String(fs.readFileSync(fullpath));
    var obj = JSON.parse(data);
    if(obj == null || ! ("type" in obj) || obj.type != "AEPrj") {
        messageToInterface(filename + " is not a valid Advanced Explorer project.")
    return;
    }

    params.project = {
      "list" : obj.list,
      "name" : fullpath
    }
    params.target = null;
    if(obj.active == "") {
        obj.active = obj.list[0];
    }
    params.path = obj.active;
    getContent(params);
}


function updateIni(params)
{
  var root = path.resolve('./');
  var fullpath = path.join(root, params.path);  
	var here = fs.existsSync(fullpath);
	if(!here) {
	    print("Ini file '" + fullpath + "' not found...");
	    return;
	}    
  var data = new String(fs.readFileSync(fullpath));
  sendToInterface({"type":"updateIni", 'content':data });
  print("Ini loaded.");  
}


function savefile(params)
{
    var fullpath = params.filename;
    let content = params.content;
    if(params.convert) {   
        var ext=path.extname(params.origin)
        if(ext == ".md") {    
            let protoMarkup = new MarkdownIt();
            content = protoMarkup.render(params.content)
        } 
    }      
    
    var err = fs.writeFileSync(fullpath, content);    
    var message = (err ? 'Not saved' : 'Saved') + ' into ' + fullpath;
    print(message);
    if(err)
        messageToInterface(message);    
    else { 
        sendToInterface({"type":'status', 'content':message });
        sendToInterface({"type":'saved' });
    }    
}

function store(params)
{
  var fullpath = path.join(process.cwd() , params.filename);

  var err = fs.writeFileSync(fullpath, params.content);
  var message = (err ? 'Not saved' : 'Saved') + ' into ' + fullpath; 
  print(message);
  sendToInterface({"type":'status', 'content':message });
}



function savePrj(params)
{
  var fullpath = params.name;

  var prj = {
    "type": "AEPrj",
    "active": params.active,
    "list": params.list
  }

  var err = fs.writeFileSync(fullpath, JSON.stringify(prj, null, "  ")); 
  var message = (err ? 'Not saved' : 'Saved') + ' into ' + fullpath;
  print(message);
  if(err)
      messageToInterface(message);
  else
      sendToInterface({"type":'status', 'content':message });
}

function saveSysFile(params)
{
  var fullpath = params.filename;
  var root = path.resolve('./');
  fullpath = path.join(root, fullpath);
  var result = fs.writeFileSync(fullpath, params.content);
  var message = "Setup " + (result ? 'Not saved' : 'Saved') + ' into ' + fullpath;
  print(message);
}



function isempty(params)
{
  var target = params.target;
  var fullpath = path.join(currpath[target], params.filename);

  fs.exists(fullpath, function (r) {
    if(!r) {
      messageToInterface("Dir not found " + fullpath);
      return;
    }
    fs.readdir(thepath, function(err, arrfiles) {
       messageToInterface(arrfile.length);
    });
  });
}

var totalsize = 0;
var totalfile = 0;

function infosub(basepath)
{
  var selection = fs.readdirSync(basepath);
  for(var i = 0; i < selection.length; i++)
  {
    var nextentry = path.join(basepath, selection[i]);
    var stats = fs.statSync(nextentry);
    if(stats.isDirectory())  {
       infosub(nextentry);
    }
    else
    if(stats.isFile())
    {
       totalsize += stats.size;
       totalfile ++;
    }
  }

}

function dirinfo(params)
{
  var target = params.target;
  var lst = params.filelist;
  totalsize = 0;
  totalfile = 0;

  for(var i = 0; i < lst.length; i++)
  {
    var fullpath = path.join(currpath[target], lst[i]);
    print("Next entry " + fullpath);
    var stats = fs.statSync(fullpath);
    if(stats.isDirectory())
    {
      infosub(fullpath);
    }
    else
    {
      totalsize += stats.size;
      totalfile++;
    }
  }
  var sizestr = "";
  if(totalsize > 1000000)  {
    var ms = parseInt(totalsize / 1000000, 10);
    sizestr = ms + " megas ("+ totalsize + " bytes)";
  }
  else {
    sizestr = totalsize + " bytes";
  }

  sendToInterface({"type":"dirinfo", "content" : sizestr +  ", in " + totalfile + " files" });
}


function makeThumbnail(filepath, data)
{
  print("Calling resizer... ");
  fs.exists(filepath, function(result) {
    var prefix = data.prefix;
    var imagefile = data.imagefile.replace(/\/\//gi, "/");
    var ext = data.ext;
    var format = data.format.toLowerCase();
    var scriptparam = " -w" + data.width + " -h"+ data.height;
    if(ext.charAt(0).toLowerCase() != format)
      scriptparam +=  " -" + format;

    scriptparam += ' ' + imagefile;
    print('Command: ' + "php " + filepath + " " + scriptparam);
    var r = runner.exec("php " + filepath + " " + scriptparam,  function(err, stdout, stderr) {
        print(stdout);
    }); // exec

    print(filepath + " launched by the server...");
    r.on('exit', function (code) {
      print('Local script terminated. Sending ' + data.thumbfile + " to the interface.");

    	fs.readFile(data.thumbfile, function(err, file) {
        print("Request completed.");
        sendToInterface({
          "type":'thumbnail', 
          'params' : data,
          'content' : new Buffer(file).toString('base64')
        });  
      }); // readfile
     }); // on exit
  });   //exists
}


var viewWindow;
var explorerWindow = function () {
    var pl = canonicalPath(`file://${rootdir}/code/rtview.js`)
    viewWindow = new BrowserWindow({
        width:900, height: 680, 
        "show":true, 
        "alwaysOnTop" : true, 
        "title" : "View content",
        "autoHideMenuBar": true,
        "webPreferences" : { 
            "nodeIntegration":false,
            "preload": pl
        }   
    });
    viewWindow.on('closed', () => {
    viewWindow = null
  })
}

exports.explorerWindow = explorerWindow; 
exports.closeWindow = function() {
  if(viewWindow != null) {
    viewWindow.close();
    viewWindow = null;
  }
}

function loadPage(filename, openflag) {
    if(viewWindow == undefined || viewWindow == null) {
        if(!openflag) return;   // from save command 
        explorerWindow();
    }
    var ext=path.extname(filename)
    if(ext == ".md") {
        var md = fs.readFileSync(filename, 'utf-8')
        const protoMarkup = new MarkdownIt();
        var html = protoMarkup.render(md)
        var temp = path.join(rootdir, 'aeditor'+ new String(Date.now()) + ".tmp")
        html="<!DOCTYPE html><html><head><meta charset=utf-8></head>\n<body>" + 
          html +  "</body>\n</html>"
        fs.writeFileSync(temp, html);

        viewWindow.loadURL(url.format({
          pathname: temp,
          protocol: 'File',
          slashes: true
        }))   
        viewWindow.webContents.on('did-finish-load', function() {
            var err = fs.unlinkSync(temp)
            if (err) print(err);
        });
        return;
    }
    viewWindow.loadURL(url.format({
      pathname: filename,
      protocol: 'File',
      slashes: true
    }))      
}


function zipify(fname) {
  if(fname.length > 2)
    if(fname.charAt(1) == ':')
      fname = fname.slice(2);

  fname = fname.replace(/\\/gi, '/');
  if(fname.charAt(0)== '/') return(fname.slice(1));
  return(fname);
}


/*
  Create an archive 
*/

function archive(params) {
  var source = params.source;
  var target = params.target;
  var orig = currpath[source];
  var dest = currpath[target];
  var zipname = params.zipname;
  var flist = params.list;
  var zipfile = path.join(dest, zipname)

  var command = params.archiver;
  if(command.charAt(0) != "/" && command.charAt(1) != ':')  
    command = path.join(process.resourcesPath, command)

  var pos = command.indexOf(" ")
  var archiver
  if(pos > 0)
    archiver = command.substr(0, pos)
  else
    archiver = command  

  if(!fs.existsSync(archiver)) {
    messageToInterface(archiver + " archiver not found.");
    return;
  }

  command += " " + path.join(dest, zipname);
  print(command)

  var current = process.cwd()
  process.chdir(orig)

  for(var i = 0; i < flist.length; i++)
  {
    var entry = flist[i];
    var filepath = path.join(orig, entry);
    var fdesc = fs.statSync(filepath);
    if (fdesc && fdesc.isDirectory())
      entry += "/*";

    command += " " + entry;
  }

  print("Archive command: " + command);

  runner.exec(command, function(err, stdout, stderr) {
      print("Terminated. "+ stderr);
      process.chdir(current)
      if(err) {
            messageToInterface("Enable to create " + zipname);
      }  
  });
}


function archive2(params) {
  var target = params.target;
  var orig = currpath[params.source];
  var dest = currpath[target];
  var zipname = params.zipname;
  var flist = params.list;

  print("Creating " + zipname + " List size : " + flist.length);

  var zipfile = new zip();

  for(var i = 0; i < flist.length; i++)  {
    var entry = flist[i];
    if(entry=='') continue;
    origpath =  path.join(orig, entry);
    var zipath = zipify(origpath);
    print("Adding " + zipath);
    var buffer = fs.readFileSync(origpath);
    zipfile.addFile(zipath, buffer, null, 0666);
  }

  zipfile.writeZip(path.join(dest, zipname));

}

function viewzip(params)
{
    var target = params.target;
    var zipname = params.path;
    print("Zip file: " + zipname);
    try {
        var zipfile = new zip(zipname);
        var zipEntries = zipfile.getEntries();
    } catch(e) {
        messageToInterface('Enable to open '+ zipname + " archive.");
        return;
    }
    var dirlist = [];
    var thedate = null;

    for(var i = 0; i < zipEntries.length; i++)
    {
        var zipEntry = zipEntries[i];
        var name = zipEntry.entryName;
        var size = zipEntry.header.size;
        if (zipEntry.isDirectory)  {
            dirlist.push( [ 'dir', name ] );
        }
        else  {
            thedate = buildDate(zipEntry.header.time);
            dirlist.push( [ 'file', name, size + '&nbsp;&nbsp;' + thedate ] );
        }
    }

	event.sender.send("filelist", JSON.stringify({
        "type":'dirdata', 
        'path': zipname,
        'list' : dirlist,
        'target' : params.target,
        'iszip': true
    } ));

  // extracts everything
  //zipfile.extractAllTo(targetpat, true);
}

function copyZipOver(data)
{
  var zipfile = data.zip;
  var filename = data.filename;
  var target = data.targetPath;
  var keepath = data.keepath;
  try
  {
    zipfile.extractEntryTo(filename, targetPath, keepath, true);
  }
  catch(e) { };  
}

function extractSub(zipfile, filename, target, keepath, overwrite)
{
  var zipEntry = zipfile.getEntry(filename);
  if(zipEntry == false) {
    print("Error in zip...");
    return false;
  }
  var targetNode = filename;
  var targetPath = currpath[target];
  if(!keepath)  {
      var pos = filename.lastIndexOf("/");
      targetNode = filename.substr(pos + 1);
  }

  var targetFile = path.join(targetPath, targetNode);

  print("Extracting file: " + filename + " to " + targetPath);
  if(!overwrite)
  {
      if(fs.existsSync(targetFile) && !overwrite)
      {
         sendToInterface({
          "type":"confirm",
          "question" : targetFile + " already exists. Overwrite?",
          "command": "copyzip",
          "filename" : filename,
          "targetFile" : targetPath,
          "zip": zipfile,
          "keepath": keepath
        });         
      }
  }
  try
  {
    zipfile.extractEntryTo(filename, targetPath, keepath, true);
  }
  catch(e) { };
  return true;
}

// Extract a file or a set from an archive

function extract(params) {
    var target = params.target;
    var zipname = fs.realpathSync(params.archive);
    var zipfile = new zip(zipname);
    var filelist = params.filelist;
    print(filelist.length+" to extract. Keep path=" + params.keepath + " Overwrite="+               params.overwrite);
    for(var i = 0; i < filelist.length; i++)   {
        var filename = filelist[i];
        extractSub(zipfile, filename, target, params.keepath, params.overwrite);
    }
    return;
}

function textinzip(params)
{
  var zipname = fs.realpathSync(params.archive);
  var zipfile = new zip(zipname);
  var entryname = params.entryname;
  print("Reading in zip " + entryname);
  var zipEntry = zipfile.getEntry(entryname);
  if(zipEntry != null && zipEntry != false)
  {
    var tempdir = process.cwd() + TEMPORARY;
    if(!fs.existsSync(tempdir)) fs.mkdir(tempdir);
    try {
      zipfile.extractEntryTo(zipEntry.entryName, tempdir, false, true);
    } 
    catch(e)
    {
      messageToInterface('Enable to extract. See the issues page.');
      return;
    }
    var tempfile = tempdir + path.basename(entryname);
    print("Loading "+ tempfile);
    loadPage('file:///' + tempfile, function() {
      fs.unlinkSync(tempfile);
    });
  }
  return;
}

function unzip(params)
{
  var target = params.target;
  var overwrite = params.overwrite; 
  var zipname = path.join(currpath[params.source], params.archive);
  zipname = fs.realpathSync(zipname);
  print("Unzip " + zipname + " to " + currpath[params.target] + " overwrite="+ overwrite);
  var zipfile = new zip(zipname);

  try {
    zipfile.extractAllTo(currpath[target], overwrite);
  } catch(e) {
    messageToInterface('Enable to extract. See the issues page.');
    return;
  }
  udpdateTarget(target)
  return;
}


function progressOn() {
  sendToInterface({ "type":"mouse",  'pointer' : 'progress' });
}

function progressOff(s) {
  sendToInterface({ "type":"mouse",  'pointer' : 'auto' });
}

exports.shell = function(params)
{
	var command = params.command;
	print("Explorer command: " + command);
    var target = null;
    if('target' in params) target = params.target;
    event = params.event;

    progressOn();

	switch(command)	{
	case 'getdir':
        subdir(params.path, target);
        getdir(params);
        break;
    case 'saveas':
        subdir(params.path, target);
        getdir(params);  
        break;
	case 'chdir':  // go to subdir or reload
        chdir(params.path, target);
        getdir(params);
        break;
	case 'godir':
        godir(params.path, target);
        getdir(params);
        break;
	case 'dirup':
        dirup(target);
        getdir(params);
        break;
	case 'rename':
        rename(params);
        break;
	case 'unlink':
        deleteEntry(params);
        break;
	case 'filecopy':
  		  filecopy(params); // will test if already existing
  		  break;
    case 'sync':
        synchronize(params);
        break;    
    case 'copyover':
        copyIf(params.path, target, false); // do not test if exists
        break;
    case 'copyzip':
        copyZipOver(command);
        break;      
	case 'getContent':
        params.project=null;
        params.newPrj = false;
        getContent(params);
        break;
    case 'openPrj':
        openProject(params);
        break;
	case 'updateIni':
        updateIni(params);
        break;      
	case 'savePrj':
		savePrj(params);
		break;      
	case 'isempty':
		filecopy(params);
		break;
	case 'archive':
		archive(params);
		break;
	case 'dirinfo':
		dirinfo(params);
		break;
	case 'loadimage':
		print("Explorer shell request filepath : " + params.path);
		readImage(params.path);
		break;
	case 'thumbnail':
		print("Building thumbnail of " + params.imagefile)
		makeThumbnail(params.path, params);
		break;
	case 'viewtext':
		loadPage(params.path, params.open);
		break;
	case 'save':
        savefile(params);
    	break;
	case 'store':
    	store(params);
    	break;      
	case 'savesys':
    	saveSysFile(params);
    	break;
	case 'viewzip':
    	viewzip(params);
    	break;
	case 'textinzip':
    	textinzip(params);
    	break;
	case 'unzip': // whole archive
    	unzip(params);
    	break;
    case 'extract':
        extract(params);
        break;  
	case 'fillbox':
        fillBox(params);
        break;
    case "boxapp":
        loadBoxApp(params);
        break;
	case 'quit':
        progressOff();
        print("Bye...");
    	process.exit(0);
    	break;
	default:
        progressOff();
        messageToInterface('Unknow command '+command+' to Explorer');
        print(command + " unknow.");
	}
  progressOff();
}
