var EXPORTED_SYMBOLS = ['GrabPicturesService'];

var Application = Components.classes["@mozilla.org/fuel/application;1"]
                  .getService(Components.interfaces.fuelIApplication);

let jsm = {};
Components.utils["import"]("resource://livemargins/utils.jsm", jsm);

// "bind" is not defined in Firefox3
if (!Function.prototype.bind) {
  Function.prototype.bind = function (context) {
    var __method = this, args = Array.prototype.slice.call(arguments, 1);
    return function() {
      return __method.apply(context, args.concat(Array.prototype.slice.call(arguments, 0)));
    }
  };
}

/***************************************************************************************
 * Basic Structure:
  Group = {
    id: id,
    title: title,
    pictures: []
  }
  Picture = {
    id: id,
    uri: uri,
    weburi: weburi,
    groupId: groupId
  }
 **************************************************************************************/
var GrabPicturesService = {
  picGroupIds: [],
  picGroups: {},
  picObjects: {},

  dao: null,

  DEFAULT_GROUP_ID: 1,

  initialized: false,
  initService: function() {
    if (this.initialized)
      return;
    this.initialized = true;

    var jsm = {};
    Components.utils.import("resource://livemargins/apps/gallery/picdao.js", jsm);
    this.dao = jsm.PictureDAO;

    this.dao.init();
    this.loadPicturesData();
  },

  getGroups: function() {
    var groups = [];
    for (var i = 0; i < this.picGroupIds.length; i += 1) {
      if (String(this.picGroupIds[i]) in this.picGroups) {
        groups.push(this.picGroups[String(this.picGroupIds[i])]);
      }
    }
    return jsm.utils.exposeReadOnly(groups);
  },

  getPicObject: function(id) {
    if (String(id) in this.picObjects) {
      return jsm.utils.exposeReadOnly(this.picObjects[String(id)]);
    }

    return null;
  },

  getGroupObject: function(id) {
    if (String(id) in this.picGroups) {
      return jsm.utils.exposeReadOnly(this.picGroups[String(id)]);
    }

    return null;
  },

  doSaveGroup: function(group, folder) {
    this.dao.saveGroup(group, folder);
  },

  doSavePictures: function(folder) {
    var groups = this.getGroups();
    this.dao.savePictures(groups, folder);
  },

  loadPicturesData: function(){
    if (this.dao) {
      // load group
      var groups = this.dao.getGroups();
      for (var i = 0; i < groups.length; i += 1) {
        var id = groups[i].id;
        this.picGroupIds.push(id);
        this.picGroups[String(id)] = {
          id: groups[i].id,
          title: groups[i].title,
          pictures: []
        };
        logObject(this.picGroups[String(id)]);
      }

      // load pictures
      var pictures = this.dao.getPictures();
      for (var i = 0; i < pictures.length; i += 1) {
        var pid = pictures[i].id;
        var gid = pictures[i].groupId;
        if (String(gid) in this.picGroups) {
          this.picGroups[String(gid)].pictures.push(pictures[i]);
          this.picObjects[String(pid)] = pictures[i];
          logObject(pictures[i]);
        } else {
          log("Something is wrong, got groupId=" + groupId + " but not in the Group map!");
        }
      }
    }
  },

  addPicture: function(uri, webUri, groupId) {
    log("add picture " + uri + ";" + webUri + ";" + groupId);

    if (!(String(groupId) in this.picGroups)) {
      log("Something is wrong, got groupId=" + groupId + " but not in the Group map!");
      return;
    }

    var pid = this.dao.addPicture(uri, webUri, groupId);
    this.dao.cachePicture(uri, false);

    var picObject = {
      id: pid,
      uri: uri,
      weburi: webUri,
      groupId: groupId
    };
    logObject(picObject);
    picObject = jsm.utils.exposeReadOnly(picObject);
    this.picGroups[String(groupId)].pictures.push(picObject);
    this.picObjects[String(pid)] = picObject;

    return pid;
  },

  removePicture: function(id, clearCache) {
    var picObject = this.getPicObject(id);
    if (picObject) {
      log("remove picture #" + id);
      if (String(picObject.groupId) in this.picGroups) {
        var group = this.picGroups[String(picObject.groupId)];
        for (var i = 0; i < group.pictures.length; i += 1) {
          if (group.pictures[i].id === picObject.id) {
            group.pictures.splice(i, 1);
            break;
          }
        }
      }
      delete this.picObjects[String(id)];

      this.dao.removePicture(id, picObject.uri, clearCache);
    }
  },

  getLocalCache:function(uri) {
    return jsm.utils.exposeReadOnly(this.dao.getLocalCache(uri));
  },

  getThumbnail: function(uri) {
    return this.dao.getThumbnail(uri);
  },

  createThumbnail: function(uri, data) {
    this.dao.createThumbnail(uri, data);
  },

  addGroup: function(title) {
    log("addgroup " + title);

    var gid = this.dao.addGroup(title);

    var groupObj = {
      id: gid,
      title: title,
      pictures: []
    };
    logObject(groupObj);
    this.picGroupIds.push(gid);
    this.picGroups[String(gid)] = groupObj;

    return jsm.utils.exposeReadOnly(groupObj);
  },

  setGroupTitle: function(id, name) {
    log('setting title ' + name + " for group #" + id);
    if (!(String(id) in this.picGroups)) {
      log("Something is wrong, the group #" + id + " is not in the map!");
      return;
    }

    var groupObj = this.picGroups[String(id)];
    groupObj.title = name;

    this.dao.updateGroup(id, name);
  },

  removeGroup: function(id) {
    log("remove group #" + id);

    if (!(String(id) in this.picGroups)) {
      log("Something is wrong, the group #" + id + " is not in the map!");
      return;
    }

    // front end will make sure that this is an empty group;

    var groupObj = this.picGroups[String(id)];
    delete this.picGroups[String(id)];
    for (var i = 0; i < this.picGroupIds.length; i += 1) {
      if (this.picGroupIds[i] == id) {
        this.picGroupIds.splice(i, 1);
        break;
      }
    }

    this.dao.removeGroup(id);
  },

  savePageAsPicture: function() {
    var main = this.mainWindow;

    var webUri = this.getCurrentTabLink();
    var localuri = this.dao.captureWindow(main, webUri);
    Application.console.log(localuri);

    if (localuri) {
      var self = this;
      this.mainWindow.setTimeout(function() {
        var picId = self.addPicture(localuri, webUri, self.DEFAULT_GROUP_ID);
      }, 1000);
    }
  },

  getFileURI: function(localuri) {
    var localfile = Components.classes["@mozilla.org/file/local;1"].
          createInstance(Components.interfaces.nsILocalFile);
    localfile.initWithPath(localuri);
    var ioService = Components.classes["@mozilla.org/network/io-service;1"].
          getService(Components.interfaces.nsIIOService);
    return ioService.newFileURI(localfile).spec;
  },

  dispose: function(){
    if (this.dao) {
      this.dao.dispose();
    }
  },

  get mainWindow() {
    var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                       .getService(Components.interfaces.nsIWindowMediator);
    var mainWindow = wm.getMostRecentWindow("navigator:browser");
    return (mainWindow);
  },

  openLink: function(link) {
    this.mainWindow.getBrowser().loadOneTab(link, null, null, null, false, false);
  },

  getCurrentTabLink: function() {
    var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                       .getService(Components.interfaces.nsIWindowMediator);
    var recentWindow = wm.getMostRecentWindow("navigator:browser");
    return recentWindow ? recentWindow.content.document.location.toString() : null;
  },

  onDragGesture: function(event) {
    var deltaX = event.endX - event.startX;
    var deltaY = event.endY - event.startY;

    if (deltaX * deltaX + deltaY * deltaY <= 64) {
      // not drag long enough I think
      return false;
    }

    if (event.type === 'image') {
      var uri = event.data;
      var webUri = this.getCurrentTabLink();
      var picId = this.addPicture(uri, webUri, this.DEFAULT_GROUP_ID);
//      this.mainWindow.marginBoxUI.openPreviewPanel(this, {
//        selectId: picId
//      });
      return true;
    }
    return false;
  },

};

GrabPicturesService.initService();

function logObject(obj) {
  var x = [];
  for (var key in obj) {
    if (typeof obj[key] === 'function') {
      x.push(key + ": function");
    } else {
      x.push([key, obj[key]].join(' = '));
    }
  }
  log(x.join('\r\n'));
}

function log(msg) {
  var debug = false;
  if (debug) {
    Application.console.log("[MB-GrabPic] " + msg);
  }
}

