/* appjet:version 0.1 */

/* appjet:library */

import('storage');
import('lib-json');

if (!storage.__export) {
   storage.__export = new StorableObject();
}

/**
* Force the Export panel view
*/
function showExportAdminPanel() {
   appjet.isPreview == true;
   enableStorageExport();
}

/**
* Allow the export of app storage
*/
function enableStorageExport() {
       if (appjet.isPreview) {
           if (request.path.match('/import')) {
               if (request.params.password) {
                   var json = serializeStorables(storage);
                   var json = wpost(request.params.url+'/export', {"password": request.params.password});
                   if (json) {
                       var obj = unserializeStorables(json);
                       if (obj) {
                           for(var x in obj) {
                               storage[x] = obj[x];
                           }
                           print(P({"class": "notice"}, "The Import has completed successfully"));
                           response.stop(true);
                       }
                   }
                   print(P({"class": "notice"}, "The Import failed!"));
               } else {
                   print(H4('Import storage from another Application'));
                   print(P("The application you are importing from must have lib-storage installed, and enabled. You must know the export password for that app."));
                   print(FORM({name: "set-pass", "method": "post"},
                       LABEL({"for": "password"}, "External App URL"),
                       INPUT({"type": "text", "name": "url"}),
                       LABEL({"for": "password"}, "External App Password"),
                       INPUT({"type": "password", "name": "password"}),
                       BUTTON({"type": "submit"}, "Import Storage from External App")
                   ));
               }
           } else if (request.path.match('/export')) {
               if (request.params.password) {
                   var json = serializeStorables(storage);
                   var result = wpost(request.params.url+'/import', {"json": json, "password": request.params.password});
                   if (result == 'ok') {
                       print(P({"class": "notice"}, "The Import has completed successfully"));
                   } else {
                       print(P({"class": "notice"}, "The Import failed!"));
                   }
               } else {
                   print(H4('Export storage to another application'));
                   print(P("The application you are exporting to must have lib-storage installed, and enabled. You must know the export password for that app."));
                   print(FORM({name: "set-pass", "method": "post"},
                       LABEL({"for": "password"}, "External App URL"),
                       INPUT({"type": "text", "name": "url"}),
                       LABEL({"for": "password"}, "External App Password"),
                       INPUT({"type": "password", "name": "password"}),
                       BUTTON({"type": "submit"}, "Export Storage to External App")
                   ));
               }
           } else if (request.path.match('/setpass')) {
               if (request.params.password) {
                   storage.__export.password = request.params.password;
                   print(P('The export password has been set'));
               } else {
                   print(H4('Set Export Password'));
                   print(P("The password you set is used to authenticate any application that wants to import your storage objects"));
                   print(FORM({name: "set-pass", "method": "post"},
                       LABEL({"for": "password"}, "Password"),
                       INPUT({"type": "password", "name": "password"}),
                       BUTTON({"type": "submit"}, "Set export Password")
                   ));
               }
           } else {
               print(H4("How to export"));
               print(P("You need to install lib-export on both apps."));
               print(P("On the app you want to export to, set an export password."));
               print(P("From the app your are exporting from, choose export, and fill in the target apps password and url.."));
               print(H4("Storage Export Menu"));
               print(UL({"class": "nav"},
                   LI({"class": "nav-item"}, A({"href": "/setpass"}, "Set Password")),
                   LI({"class": "nav-item"}, A({"href": "/export"}, "Export")),
                   LI({"class": "nav-item"}, A({"href": "/import"}, "Import"))
               ));
           }
           response.stop(true);
       } else if (request.path.match('/export')) {
           if (request.params.password == storage.__export.password) {
               page.setMode('plain');
               var json = serializeStorables(storage);
               print(json);
           }
           response.stop(true);
       } else if (request.path.match('/import')) {
           if (request.params.password == storage.__export.password) {
               page.setMode('plain');
               var obj = unserializeStorables(request.params.json);
               if (obj) {
                   for(var x in obj) {
                       storage[x] = obj[x];
                   }
                   print('ok');
               } else {
                   print('fail');
               }
           }
           response.stop(true);
       }
}

/**
* Recursively convert a storable object into native JavaScript Object
* @param {storage} Object storable Object or global storage
*/
function objectizeStorables(storage) {
   if (typeof storage == 'object') {
       var obj = {};
       for(var x in storage) {
           if (x == '__export') continue;
           if (storage[x] instanceof StorableCollection) {
               obj[x] = [];
               storage[x].forEach(function(_obj) {
                   obj[x].push(objectizeStorables(_obj));
               });
           } else if (storage[x] instanceof StorableObject) {
               obj[x] = {};
               for(var y in storage[x]) {
                   if (storage[x].hasOwnProperty(y)) {
                       obj[x][y] = objectizeStorables(storage[x][y]);
                   }
               }
           } else {
               obj[x] = storage[x];
           }
       }
       return obj;
   }
   return storage;
}

/**
* Serialize a Storable Object to JSON
* @param {storage} Object storable Object or global storage
*/
function serializeStorables(storage) {
   return JSON.stringify(objectizeStorables(storage));
}

/**
* Recursively convert native Objects to storable Object
* @param {obj} Object Native JavaScript Object
*/
function storablelizeObjects(obj) {
   if (object instanceof Object) {
       var storage = {};
       for(var x in obj) {
           if (obj[x] instanceof Array) {
               storage[x] = new StorableCollection();
               obj[x].forEach(function(_obj) {
                   storage[x].add(storablelizeObjects(_obj));
               });
           } else if (obj[x] instanceof Object) {
               storage[x] = new StorableObject();
               for(var y in storage[x]) {
                   if (storage[x].hasOwnProperty(y)) {
                       storage[x][y] = storablelizeObjects(obj[x][y]);
                   }
               }
           } else {
               storage[x] = obj[x];
           }
       }
       return storage;
   }
   return obj;
}

/**
* Unserialize a JSON string into a Storable Object
* Objects become StorableObject and Arrays become StorableCollection Instances
* @param json {String} JSON encode string
*/
function unserializeStorables(json) {
   try {
       var obj = JSON.parse(json);
       var Storable = storablelizeObjects(obj);
       return Storable;
   } catch(e) {
       return false;
   }
}