
const DEBUG = false;         

const BOKEE_PHOTO_CID               = Components.ID('{e45f9819-0648-438d-ba87-0b0bef79e92e}');

const nsISupports                   = Components.interfaces.nsISupports;
const nsIClassInfo                  = Components.interfaces.nsIClassInfo;
const nsIFactory                    = Components.interfaces.nsIFactory;
const nsIProperties                 = Components.interfaces.nsIProperties;
const nsILocalFile                  = Components.interfaces.nsILocalFile;
const nsIFile                       = Components.interfaces.nsIFile;
const nsIIOService                  = Components.interfaces.nsIIOService;
const nsIFileProtocolHandler        = Components.interfaces.nsIFileProtocolHandler;
const nsIRDFRemoteDataSource        = Components.interfaces.nsIRDFRemoteDataSource;
const nsIRDFDataSource              = Components.interfaces.nsIRDFDataSource;
const flockIPhotoAPI                = Components.interfaces.flockIPhotoAPI;

const BOKEE_PHOTO_CONTRACTID        = '@flock.com/?photo-api-bokee;1';
const DIRECTORY_SERVICE_CONTRACTID  = '@mozilla.org/file/directory_service;1';
const LOCAL_FILE_CONTRACTID         = '@mozilla.org/file/local;1';
const PREFERENCES_CONTRACTID        = '@mozilla.org/preferences-service;1';
const IO_SERVICE_CONTRACTID         = '@mozilla.org/network/io-service;1';

//const BOKEE_LOGIN_URL               = 'http://reg.bokee.com/account/web/login.jsp';
const BOKEE_LOGIN_URL               = 'http://photo.bokee.com/photoblog/PhotoBlogCtrl?page=LoginCtrlPage';
const BOKEE_UPLOAD_URL              = 'http://photo.bokee.com/photoblog/xml-rpc-upload';
const BOKEE_API_URL                 = 'http://photo.bokee.com/photoblog/APICtrl?';
//const BOKEE_LOGOUT_URL              = 'http://photo.bokee.com/photoblog/logoutCtrl';

/*
var BokeeAPI = {
    state : function() {
    getAuthUser : function() {
        var authUser = {
            id: "anthony",
            username: "anthony",
            fullname: "anthony",
        };
        return authUser;
    },
};
*/

const Base64 = {
    chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
    encode: function (aInput) {
        var output = '';
        while (aInput.length > 0) {
            output += Base64.chars[aInput.charCodeAt(0) >> 2];
            output += Base64.chars[((aInput.charCodeAt(0)&0x03) << 4) | 
                (aInput.length>1?((aInput.charCodeAt(1)&0xF0) >> 4):0)];
            output += Base64.chars[aInput.length>1?
                ((aInput.charCodeAt(1)&0x0F)<<2) | 
                (aInput.length>2?((aInput.charCodeAt(2)&0xC0) >> 6):0):64];
            output += Base64.chars[aInput.length>2?
                (aInput.charCodeAt(2)&0x3F):64];
            if (aInput.length > 3) {
                aInput = aInput.substr (3);
            } else {
                break;
            }
        }
        return output;
    },
    decode: function (aInput) {
        const regexp = new RegExp ('[^'+Base64.chars+']', 'g');
        var output = '';

        aInput = aInput.replace (regexp, '');

        // FIXME: aInput MUST now be a multiple of four characters long

        function sixbits (i) {
            if (i == '=') return 0;
            return Base64.chars.indexOf (i);
        }

        while (aInput.length >= 4) {
            output += String.fromCharCode ((sixbits (aInput[0]) << 2) | 
                    (sixbits (aInput[1]) >> 4));
            if (aInput[2] == '=') {
                break;
            }
            output += String.fromCharCode ((sixbits (aInput[1]) << 4) |
                    (sixbits (aInput[2]) >>2));
            if (aInput[3] == '=') {
                break;
            }
            output += String.fromCharCode (((sixbits (aInput[2]) << 6) & 0xC0) |
                    sixbits (aInput[3]));
            aInput = aInput.substr (4);
        }
        return output;
    },
}

function bokeePhotoService() { /*{{{*/
    debug ('CONSTRUCTOR: bokeePhotoService\n');
//    this.init();
//    this.state = flockIPhotoAPI.LOGGED_OUT;
    this.state = flockIPhotoAPI.LOGGED_OUT;
    this.init();

}/*}}}*/

bokeePhotoService.prototype.state = flockIPhotoAPI.LOGGED_OUT;
bokeePhotoService.prototype.mAuthUser = null;
bokeePhotoService.prototype.mUploader = null;

bokeePhotoService.prototype.init = function () { /*{{{*/
    this.updateLogin();
    //check cookie to see if we are logged in
}/*}}}*/

bokeePhotoService.prototype.getAuthState = function () { /*{{{*/
    return this.state;
}/*}}}*/

bokeePhotoService.prototype.logout = function () { /*{{{*/
    var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"].
        getService(Components.interfaces.nsICookieManager);
    cookieManager.remove(".bokee.com","bokie","/",false);
    this.updateLogin();
}/*}}}*/

bokeePhotoService.prototype.updateLogin = function (aListener) { /*{{{*/
    var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"].
        getService(Components.interfaces.nsICookieManager2);
    var enumerator = cookieManager.enumerator;
    var count = 0;
    this.state = flockIPhotoAPI.LOGGED_OUT;
    this.mAuthUser = null;
    while (enumerator.hasMoreElements()) {
         var nextCookie = enumerator.getNext();
         nextCookie = nextCookie.QueryInterface(Components.interfaces.nsICookie);
         var host = nextCookie.host;
         var name = nextCookie.name;
         var value = nextCookie.value;
         if(host==".bokee.com" && name=="bokie") {
            value = Base64.decode(value);
            debug(host + " " + name + " " + value + "\n");
            var values = value.split(",");
            var username = values[0];
            //deal with encoding crap to extract id
            var id = values[2];
            id = escape(id);
            id = id.replace(/%u022/g, ",");
            id = id.replace(/%u033/g, "");
            id = id.replace(/%u023/g, "");
            id = id.split(",")[0];
            this.state = flockIPhotoAPI.LOGGED_IN;
            this.mAuthUser = {
                username: username,
                id: id,
                fullname: username,
            };
         }
    }
}/*}}}*/

bokeePhotoService.prototype.doLogin = function (aListener) { /*{{{*/
    this.updateLogin();
    if(this.state==flockIPhotoAPI.LOGGED_IN) {
        aListener.onAuth();
        return;
    }

    var windowManager = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
    var windowManagerInterface = windowManager.QueryInterface( Components.interfaces.nsIWindowMediator);
    var topWindow = windowManagerInterface.getMostRecentWindow(null);
    topWindow.open(BOKEE_LOGIN_URL,"_blank", "chrome,close,titlebar,resizable=yes,toolbar,dialog=no,scrollbars=yes,modal,centerscreen");

    this.updateLogin();
    if(this.state==flockIPhotoAPI.LOGGED_IN) {
        aListener.onAuth();
    }
    else {
        aListener.onError("localize this: error logging in");
    }
}

bokeePhotoService.prototype.login = function (aListener) { /*{{{*/
    if(this.state==flockIPhotoAPI.LOGGING_IN) return;
    this.state=flockIPhotoAPI.LOGGING_IN;

    var timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
    var inst = this;
    timerFunc = {
        notify: function(aTimer) {
            inst.doLogin(aListener);
        },
    }
    timer.initWithCallback(timerFunc,0,0);//re-check token

}/*}}}*/

bokeePhotoService.prototype.isLoggedIn = function (aListener) { /*{{{*/
    return (this.state == flockIPhotoAPI.LOGGED_IN);
}/*}}}*/

bokeePhotoService.prototype.dictionary2Params = function (aDictionary) { /*{{{*/
    var params = {};
    var obj = {};
    var count = {};
    var keys = aDictionary.getKeys(count, obj);
    for(var i=0;i<keys.length;++i) {
        var supports = aDictionary.getValue(keys[i]);
        var supportsString = supports.QueryInterface(Components.interfaces.nsISupportsString);
        var val = supportsString.toString();
        params[keys[i]] = val;
    }
    return params;
}/*}}}*/

bokeePhotoService.prototype.getAuthUser = function () { /*{{{*/
//    debug(this.mAuthUser + " asdasdasdasjdhasdkjadsdhaskjdhaskjdhaskjdhaskjdhasdkjahsdkjashdkadsjd\n");
    return this.mAuthUser;
}/*}}}*/

bokeePhotoService.prototype.isUploading = function () { /*{{{*/
    return false;
}/*}}}*/

bokeePhotoService.prototype.call = function (aListener, aMethod, aDictionary) { /*{{{*/
    var params = this.dictionary2Params(aDictionary);
    var qs = "";
    for(var p in params) {
        qs += "&" + escape(p) + "=" + escape(params[p]); 
    }
    var url = BOKEE_API_URL + "page=" + aMethod + qs;

    debug(url + " < call\n");
    this.req = Components.classes[XMLHTTPREQUEST_CONTRACTID].createInstance(nsIXMLHttpRequest);
    this.req.open('GET', url, true);
    var req = this.req;
    this.req.onreadystatechange = function (aEvt) {
        if(req.readyState == 4) {
            try {
                if(req.status/100 == 2) {
                    debug("\n" + req.responseText + "\n");
                    var rsp = req.responseXML.getElementsByTagName("rsp")[0];
                    var stat = rsp.getAttribute("stat");
                    if(stat!="ok") {
                        var err = req.responseXML.getElementsByTagName("err")[0];
                        aListener.onError(unescape(err.getAttribute("code")));
                    }
                    else {
                        aListener.onResult(req.responseXML);
                    }
                }
                else {
                    aListener.onError(null);
                }
            } catch(e) {
                debug(e);
                aListener.onError(null);
            }
        }
    }
    this.req.send(null);
    
}/*}}}*/

bokeePhotoService.prototype.authenticatedCall = function (aListener, aMethod, aDictionary) { /*{{{*/
    if(!this.isLoggedIn()) {
        aListener.onError("you must be logged in before using authenticatedCall");
        return;
    }
    return this.call(aListener, aMethod, aDictionary);
}/*}}}*/

bokeePhotoService.prototype.upload = function (aListener, aFile, aDictionary) { /*{{{*/
    if(!this.isLoggedIn()) throw "Error - assertion failure, should be loggedin";
    var params = this.dictionary2Params(aDictionary);
    this.mUploader = new PhotoUploader();
    var myListener = {
        onResult: function(aXML) {
            var photo = aXML.getElementsByTagName("photo")[0];
            //var stat = rsp.getAttribute("stat");
            if(photo) {
                aListener.onResult(aXML);
            }
            else {
                var rsp = aXML.getElementsByTagName("rsp")[0];
                var err = aXML.getElementsByTagName("err")[0];
                aListener.onError(unescape(err.getAttribute("code")));
            }
        },
        onError: function(aXML) {
            aListener.onError(aXML);
        },
    }
//    params.username = this.mAuthUser.username;
    for(var p in params) {
        debug(p + " " + params[p] + "\n");
    }


    var myParams = {};
    myParams.title = params.title;
    myParams.tags = params.tags;
    myParams.description = params.description;
    var is_public = (params.is_public + "" == "true");
    var is_family = (params.is_family + "" == "true");
    var is_friend = (params.is_friend + "" == "true");
    // 0==public
    // 0==public
    myParams.is_public="1";//private
    if(is_public) {
        myParams.is_public="0";
    }
    else if(is_family && is_friend) {
        myParams.is_public="4";
    }
    else if(is_family) {
        myParams.is_public="3";
    }
    else if(is_friend) {
        myParams.is_public="2";
    }
    
    this.mUploader.setEndpoint(BOKEE_UPLOAD_URL);

    this.mUploader.upload(myListener, aFile, myParams);
}/*}}}*/

bokeePhotoService.prototype.cancelUpload = function () { /*{{{*/
    try { this.mUploader.req.abort(); }
    catch(e){};
}/*}}}*/

loadLibraryFromSpec('chrome://browser/content/flock/common/flocksafe.js');
loadLibraryFromSpec("chrome://browser/content/flock/photo/photoAPI.js");

function loadLibraryFromSpec(aSpec) {
    var loader = Components.classes['@mozilla.org/moz/jssubscript-loader;1']
        .getService(Components.interfaces.mozIJSSubScriptLoader);

    loader.loadSubScript(aSpec);
}

bokeePhotoService.prototype.flags = nsIClassInfo.SINGLETON;
bokeePhotoService.prototype.classDescription = "Bokee Photo Service";
bokeePhotoService.prototype.getInterfaces = function (count) {
    var interfaceList = [flockIPhotoAPI, nsIClassInfo];
    count.value = interfaceList.length;
    return interfaceList;
}
bokeePhotoService.prototype.getHelperForLanguage = function (count) {return null;}/*}}}*/

// the nsISupports implementation/*{{{*/
bokeePhotoService.prototype.QueryInterface =
function (iid) {
    if (!iid.equals(flockIPhotoAPI) && 
        !iid.equals(nsIClassInfo) &&
        !iid.equals(nsISupports))
        throw Components.results.NS_ERROR_NO_INTERFACE;
    if (iid.equals(nsIRDFDataSource) && !this.dataSourceSetup) {
    }
    return this;
}/*}}}*/

// Module implementation/*{{{*/
var PhotoModule = new Object();

PhotoModule.registerSelf =
function (compMgr, fileSpec, location, type)
{
    compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);

    compMgr.registerFactoryLocation(BOKEE_PHOTO_CID, 
                                    "Bokee Photo JS Component",
                                    BOKEE_PHOTO_CONTRACTID, 
                                    fileSpec, 
                                    location,
                                    type);
}

PhotoModule.getClassObject =
function (compMgr, cid, iid) {
    if (!cid.equals(BOKEE_PHOTO_CID))
        throw Components.results.NS_ERROR_NO_INTERFACE;
    
    if (!iid.equals(Components.interfaces.nsIFactory))
        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
    
    return PhotoServiceFactory;
}

PhotoModule.canUnload =
function(compMgr)
{
    debug("Unloading component.");
    return true;
}/*}}}*/
    
/* factory object *//*{{{*/
var PhotoServiceFactory = new Object();

PhotoServiceFactory.createInstance =
function (outer, iid) {
    debug("CI: " + iid + "\n");
    if (outer != null)
        throw Components.results.NS_ERROR_NO_AGGREGATION;

    return (new bokeePhotoService()).QueryInterface(iid);
}/*}}}*/

/* entrypoint *//*{{{*/
function NSGetModule(compMgr, fileSpec) {
    return PhotoModule;
}/*}}}*/
