/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

// Component constants
const CC = Components.classes;
const CI = Components.interfaces;
const CU = Components.utils;

CU.import("resource://gre/modules/XPCOMUtils.jsm");
CU.import("resource://gre/modules/Services.jsm");

const CURRENT_MIGRATION = 8;

function Status_4_Evar(){}

Status_4_Evar.prototype =
{
  classID:        Components.ID("{33d0433d-07be-4dc4-87fd-954057310efd}"),
  QueryInterface: XPCOMUtils.generateQI([
                       CI.nsISupportsWeakReference,
                       CI.nsIObserver,
                       CI.nsIStatus4Evar
                  ]),

  prefs:          null,

  addonbarBorderStyle:            false,
  addonbarCloseButton:            false,
  addonbarWindowGripper:          true,

  advancedStatusDetectFullScreen: true,
  advancedStatusDetectVideo:      true,

  downloadButtonAction:           1,
  downloadButtonActionCommand:    "",
  downloadColorActive:            null,
  downloadColorPaused:            null,
  downloadForce:                  false,
  downloadLabel:                  0,
  downloadLabelForce:             true,
  downloadNotifyAnimate:          true,
  downloadNotifyTimeout:          60000,
  downloadProgress:               1,
  downloadTooltip:                1,

  firstRun:                       true,

  progressToolbarCSS:             null,
  progressToolbarForce:           false,
  progressToolbarStyle:           false,

  status:                         1,
  statusDefault:                  true,
  statusNetwork:                  true,
  statusTimeout:                  10000,
  statusLinkOver:                 1,
  statusLinkOverDelayShow:        70,
  statusLinkOverDelayHide:        150,

  statusToolbarMaxLength:         0,

  statusToolbarInvertMirror:       false,
  statusToolbarMouseMirror:        true,

  pref_registry:
  {
    "addonbar.borderStyle":
    {
      update: function()
      {
        this.addonbarBorderStyle = this.prefs.getBoolPref("addonbar.borderStyle");
      },
      updateWindow: function(win)
      {
        let browser_bottom_box = win.caligon.status4evar.getters.browserBottomBox;
        if(browser_bottom_box)
        {
          this.setBoolElementAttribute(browser_bottom_box, "s4eboarder", this.addonbarBorderStyle);
        }
      }
    },

    "addonbar.closeButton":
    {
      update: function()
      {
        this.addonbarCloseButton = this.prefs.getBoolPref("addonbar.closeButton");
      },
      updateWindow: function(win)
      {
        let addonbar_close_button = win.caligon.status4evar.getters.addonbarCloseButton;
        if(addonbar_close_button)
        {
          addonbar_close_button.hidden = !this.addonbarCloseButton;
        } 
      }
    },

    "addonbar.windowGripper":
    {
      update: function()
      {
        this.addonbarWindowGripper = this.prefs.getBoolPref("addonbar.windowGripper");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.toolbars.updateWindowGripper(true);
      }
    },

    "advanced.status.detectFullScreen":
    {
      update: function()
      {
        this.advancedStatusDetectFullScreen = this.prefs.getBoolPref("advanced.status.detectFullScreen");
      }
    },

    "advanced.status.detectVideo":
    {
      update: function()
      {
        this.advancedStatusDetectVideo = this.prefs.getBoolPref("advanced.status.detectVideo");
      }
    },

    "download.button.action":
    {
      update: function()
      {
        this.downloadButtonAction = this.prefs.getIntPref("download.button.action");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.downloadStatus.updateBinding();
      }
    },

    "download.button.action.command":
    {
      update: function()
      {
        this.downloadButtonActionCommand = this.prefs.getCharPref("download.button.action.command");
      }
    },

    "download.color.active":
    {
      update: function()
      {
        this.downloadColorActive = this.prefs.getCharPref("download.color.active");
      },
      updateDynamicStyle: function(sheet)
      {
        sheet.cssRules[2].style.backgroundColor = this.downloadColorActive;
      }
    },

    "download.color.paused":
    {
      update: function()
      {
        this.downloadColorPaused = this.prefs.getCharPref("download.color.paused");
      },
      updateDynamicStyle: function(sheet)
      {
        sheet.cssRules[3].style.backgroundColor = this.downloadColorPaused;
      }
    },

    "download.force":
    {
      update: function()
      {
        this.downloadForce = this.prefs.getBoolPref("download.force");
      },
      updateWindow: function(win)
      {
        let download_button = win.caligon.status4evar.getters.downloadButton;
        if(download_button)
        {
          this.setBoolElementAttribute(download_button, "forcevisible", this.downloadForce);
        }

        let download_notify_anchor = win.caligon.status4evar.getters.downloadNotifyAnchor;
        this.setBoolElementAttribute(download_notify_anchor, "forcevisible", this.downloadForce);
      }
    },

    "download.label":
    {
      update: function()
      {
        this.downloadLabel = this.prefs.getIntPref("download.label");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.downloadStatus.updateButton();
      }
    },

    "download.label.force":
    {
      update: function()
      {
        this.downloadLabelForce = this.prefs.getBoolPref("download.label.force");
      },
      updateWindow: function(win)
      {
        let download_button = win.caligon.status4evar.getters.downloadButton;
        if(download_button)
        {
          this.setBoolElementAttribute(download_button, "forcelabel", this.downloadLabelForce);
        }
      }
    },

    "download.notify.animate":
    {
      update: function()
      {
        this.downloadNotifyAnimate = this.prefs.getBoolPref("download.notify.animate");
      }
    },

    "download.notify.timeout":
    {
      update: function()
      {
        this.downloadNotifyTimeout = (this.prefs.getIntPref("download.notify.timeout") * 1000);
      }
    },

    "download.progress":
    {
      update: function()
      {
        this.downloadProgress = this.prefs.getIntPref("download.progress");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.downloadStatus.updateButton();
      }
    },

    "download.tooltip":
    {
      update: function()
      {
        this.downloadTooltip = this.prefs.getIntPref("download.tooltip");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.downloadStatus.updateButton();
      }
    },

    "progress.toolbar.css":
    {
      update: function()
      {
        this.progressToolbarCSS = this.prefs.getCharPref("progress.toolbar.css");
      },
      updateDynamicStyle: function(sheet)
      {
        sheet.cssRules[1].style.background = this.progressToolbarCSS;
      }
    },

    "progress.toolbar.force":
    {
      update: function()
      {
        this.progressToolbarForce = this.prefs.getBoolPref("progress.toolbar.force");
      },
      updateWindow: function(win)
      {
        let toolbar_progress = win.caligon.status4evar.getters.toolbarProgress;
        if(toolbar_progress)
        {
          this.setBoolElementAttribute(toolbar_progress, "forcevisible", this.progressToolbarForce);
        }
      }
    },

    "progress.toolbar.style":
    {
      update: function()
      {
        this.progressToolbarStyle = this.prefs.getBoolPref("progress.toolbar.style");
      },
      updateWindow: function(win)
      {
        let toolbar_progress = win.caligon.status4evar.getters.toolbarProgress;
        if(toolbar_progress)
        {
          this.setBoolElementAttribute(toolbar_progress, "s4estyle", this.progressToolbarStyle);
        }
      }
    },

    "status":
    {
      update: function()
      {
        this.status = this.prefs.getIntPref("status");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.statusService.clearStatusField();
        win.caligon.status4evar.statusService.updateStatusField(true);
      }
    },

    "status.default":
    {
      update: function()
      {
        this.statusDefault = this.prefs.getBoolPref("status.default");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.statusService.buildTextOrder();
        win.caligon.status4evar.statusService.updateStatusField(true);
      }
    },

    "status.linkOver":
    {
      update: function()
      {
        this.statusLinkOver = this.prefs.getIntPref("status.linkOver");
      }
    },

    "status.linkOver.delay.show":
    {
      update: function()
      {
        this.statusLinkOverDelayShow = this.prefs.getIntPref("status.linkOver.delay.show");
      }
    },

    "status.linkOver.delay.hide":
    {
      update: function()
      {
        this.statusLinkOverDelayHide = this.prefs.getIntPref("status.linkOver.delay.hide");
      }
    },

    "status.network":
    {
      update: function()
      {
        this.statusNetwork = this.prefs.getBoolPref("status.network");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.statusService.buildTextOrder();
      }
    },

    "status.network.xhr":
    {
      update: function()
      {
        this.statusNetworkXHR = this.prefs.getBoolPref("status.network.xhr");
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.statusService.buildTextOrder();
      }
    },

    "status.timeout":
    {
      update: function()
      {
        this.statusTimeout = (this.prefs.getIntPref("status.timeout") * 1000);
      },
      updateWindow: function(win)
      {
        win.caligon.status4evar.statusService.updateStatusField(true);
      }
    },

    "status.toolbar.maxLength":
    {
      update: function()
      {
        this.statusToolbarMaxLength = this.prefs.getIntPref("status.toolbar.maxLength");
      },
      updateWindow: function(win)
      {
        let status_widget = win.caligon.status4evar.getters.statusWidget;
        if(status_widget)
        {
          status_widget.maxWidth = (this.statusToolbarMaxLength || "");
        }
      }
    },

    "status.popup.invertMirror":
    {
      update: function()
      {
        this.statusToolbarInvertMirror = this.prefs.getBoolPref("status.popup.invertMirror");
      },
      updateWindow: function(win)
      {
        let statusOverlay = win.caligon.status4evar.getters.statusOverlay;
        if(statusOverlay)
        {
          statusOverlay.invertMirror = this.statusToolbarInvertMirror;
        }
      }
    },

    "status.popup.mouseMirror":
    {
      update: function()
      {
        this.statusToolbarMouseMirror = this.prefs.getBoolPref("status.popup.mouseMirror");
      },
      updateWindow: function(win)
      {
        let statusOverlay = win.caligon.status4evar.getters.statusOverlay;
        if(statusOverlay)
        {
          statusOverlay.mouseMirror = this.statusToolbarMouseMirror;
        }
      }
    }

  },

  // nsIObserver
  observe: function(subject, topic, data)
  {
    try
    {
      switch(topic)
      {
        case "profile-after-change":
          this.startup();
          break;
        case "quit-application":
          this.shutdown();
          break;
        case "nsPref:changed":
          this.updatePref(data, true);
          break;
      }
    }
    catch(e)
    {
      CU.reportError(e);
    }
  },

  startup: function()
  {
    this.prefs = Services.prefs.getBranch("status4evar.").QueryInterface(CI.nsIPrefBranch2);

    this.firstRun = this.prefs.getBoolPref("firstRun");
    if(this.firstRun)
    {
      this.prefs.setBoolPref("firstRun", false);
    }

    this.migrate();

    for(let pref in this.pref_registry)
    {
      let pro = this.pref_registry[pref];

      pro.update = pro.update.bind(this);
      if(pro.updateWindow)
      {
        pro.updateWindow = pro.updateWindow.bind(this);
      }
      if(pro.updateDynamicStyle)
      {
        pro.updateDynamicStyle = pro.updateDynamicStyle.bind(this);
      }

      this.prefs.addObserver(pref, this, true);

      this.updatePref(pref, false);
    }

    Services.obs.addObserver(this, "quit-application", true);
  },

  shutdown: function()
  {
    Services.obs.removeObserver(this, "quit-application");

    for(let pref in this.pref_registry)
    {
      this.prefs.removeObserver(pref, this);
    }

    this.prefs = null;
  },

  migrate: function()
  {
    if(!this.firstRun)
    {
      let migration = 0;
      try
      {
        migration = this.prefs.getIntPref("migration");
      }
      catch(e) {}

      switch(migration)
      {
        case 5:
          this.migrateBoolPref("status.detectFullScreen", "advanced.status.detectFullScreen");
        case 6:
          let oldDownloadAction = this.prefs.getIntPref("download.button.action");
          let newDownloadAction = 1;
          switch(oldDownloadAction)
          {
            case 2:
              newDownloadAction = 1;
              break;
            case 3:
              newDownloadAction = 2;
              break;
            case 4:
              newDownloadAction = 1;
              break;
          }
          this.prefs.setIntPref("download.button.action", newDownloadAction);
        case 7:
            let progressLocation = this.prefs.getIntPref("status");
            if (progressLocation == 2)
              this.prefs.setIntPref("status", 1);
            let linkOverLocation = this.prefs.getIntPref("status.linkOver");
            if (linkOverLocation == 2)
              this.prefs.setIntPref("status.linkOver", 1);
            break;
        case CURRENT_MIGRATION:
          break;
      }
    }

    this.prefs.setIntPref("migration", CURRENT_MIGRATION);
  },

  migrateBoolPref: function(oldPref, newPref)
  {
    if(this.prefs.prefHasUserValue(oldPref))
    {
      this.prefs.setBoolPref(newPref, this.prefs.getBoolPref(oldPref));
      this.prefs.clearUserPref(oldPref);
    }
  },

  migrateIntPref: function(oldPref, newPref)
  {
    if(this.prefs.prefHasUserValue(oldPref))
    {
      this.prefs.setIntPref(newPref, this.prefs.getIntPref(oldPref));
      this.prefs.clearUserPref(oldPref);
    }
  },

  migrateCharPref: function(oldPref, newPref)
  {
    if(this.prefs.prefHasUserValue(oldPref))
    {
      this.prefs.setCharPref(newPref, this.prefs.getCharPref(oldPref));
      this.prefs.clearUserPref(oldPref);
    }
  },

  updatePref: function(pref, updateWindows)
  {
    if(!(pref in this.pref_registry))
    {
      return;
    }
    let pro = this.pref_registry[pref];

    pro.update();

    if(updateWindows)
    {
      let windowsEnum = Services.wm.getEnumerator("navigator:browser");
      while(windowsEnum.hasMoreElements())
      {
        this.updateWindow(windowsEnum.getNext(), pro);
      }
    }

    if(pro.alsoUpdate)
    {
      pro.alsoUpdate.forEach(function (alsoPref)
      {
        this.updatePref(alsoPref);
      }, this);
    }
  },

  // Updtate a browser window
  updateWindow: function(win, pro)
  {
    if(!(win instanceof CI.nsIDOMWindow)
    || !(win.document.documentElement.getAttribute("windowtype") == "navigator:browser"))
    {
      return;
    }

    if(pro)
    {
      this.handlePro(win, pro);
    }
    else
    {
      for(let pref in this.pref_registry)
      {
        this.handlePro(win, this.pref_registry[pref]);
      }
    }
  },

  handlePro: function(win, pro)
  {
    if(pro.updateWindow)
    {
      pro.updateWindow(win);
    }

    if(pro.updateDynamicStyle)
    {
      let styleSheets = win.document.styleSheets;
      for(let i = 0; i < styleSheets.length; i++)
      {
        let styleSheet = styleSheets[i];
        if(styleSheet.href == "chrome://browser/skin/statusbar/dynamic.css")
        {
          pro.updateDynamicStyle(styleSheet);
          break;
        }
      }
    }
  },

  setBoolElementAttribute: function(elem, attr, val)
  {
    if(val)
    {
      elem.setAttribute(attr, "true");
    }
    else
    {
      elem.removeAttribute(attr);
    }
  },

  setStringElementAttribute: function(elem, attr, val)
  {
    if(val)
    {
      elem.setAttribute(attr, val);
    }
    else
    {
      elem.removeAttribute(attr);
    }
  },

  resetPrefs: function()
  {
    let childPrefs = this.prefs.getChildList("");
    childPrefs.forEach(function(pref)
    {
      if(this.prefs.prefHasUserValue(pref))
      {
        this.prefs.clearUserPref(pref);
      }
    }, this);
  }
};

const NSGetFactory = XPCOMUtils.generateNSGetFactory([Status_4_Evar]);