// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2009
// http://flock.com
//
// This file may be used under the terms of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL

Components.utils.import("resource:///modules/FlockDateFormatter.jsm");
Components.utils.import("resource:///modules/FlockMediaUtils.jsm");
Components.utils.import("resource:///modules/FlockPrefsUtils.jsm");
Components.utils.import("resource:///modules/FlockSvcUtils.jsm");
Components.utils.import("resource:///modules/FlockURLUtils.jsm");
Components.utils.import("resource:///modules/FlockXMLUtils.jsm");

const CLASS_SHORT_NAME = "twitter";
const TWITTER_SEARCH_URN = "urn:flock:twitter:search";
const TWITTER_CONTRACT_ID = "@flock.com/people/twitter;1";
const TWITTERSEARCH_CONTRACT_ID = "@flock.com/webservice/twittersearch;1";
const FLOCK_SNOWMAN_URL = "chrome://flock/skin/people/no_avatar.png";
const TWITTER_DEFAULT_AVATAR
  = "http://static.twitter.com/images/default_profile_normal.png";
const DISABLE_TWITTER_SIDEBAR_REPLY_PREF
  = "flock.myworld.twitter.sidebarReply.disabled";

// Deck constants
const DECK_NO_SEARCH = 0;
const DECK_THROBBER = 1;
const DECK_RESULTS = 2;
const DECK_NO_RESULTS = 3;

var acUtils = Cc["@flock.com/account-utils;1"]
              .getService(Ci.flockIAccountUtils);

var gTwitterSearch;

var draggingObserver = {
  onDragStart: function twittersearch_onDragStart(aEvent,
                                               aTransferData,
                                               aAction)
  {
    var fromUsername = aEvent.target.getAttribute("fromUsername");
    var tweetId = aEvent.target.getAttribute("tweetId");
    var status = aEvent.target.getAttribute("status");

    if (!fromUsername || !tweetId) {
      return;
    }

    var url = gTwitterSearch._wd
                            .getString(CLASS_SHORT_NAME, "tweetURL", "")
                            .replace("%username%", fromUsername)
                            .replace("%tweetid%", tweetId);

    aTransferData.data = new TransferData();
    aTransferData.data.addDataForFlavour("text/x-moz-url", url + "\n" + status);
    var link = "<a href='" + url + "'>" + status + "</a>";
    aTransferData.data.addDataForFlavour("text/html", link);
    aTransferData.data.addDataForFlavour("text/unicode", url);
  },
  onDragOver: function twittersearch_onDragOver(aEvent, aTransferData, aAction)
  {
  },
  onDrop: function twittersearch_onDrop(aEvent, aTransferData, aAction)
  {
  },
  onDragExit: function twittersearch_onDragExit(aEvent, aTransferData, aAction)
  {
  }
}

function TwitterSearch() {
  this._logger = Cc["@flock.com/logger;1"]
                 .createInstance(Ci.flockILogger);
  this._logger.init("TwitterSearch");
  this._twitterSvc = Cc[TWITTER_CONTRACT_ID].getService(Ci.flockIWebService);
  this._rdfSvc = Cc["@mozilla.org/rdf/rdf-service;1"]
                 .getService(Ci.nsIRDFService);
  this._ds = this._rdfSvc.GetDataSource("rdf:flock-favorites");
  this._coop = Cc["@flock.com/singleton;1"]
               .getService(Ci.flockISingleton)
               .getSingleton("chrome://flock/content/common/load-faves-coop.js")
               .wrappedJSObject;
  this._wd = Cc["@flock.com/web-detective;1"].getService(Ci.flockIWebDetective);
}

TwitterSearch.prototype.init =
function TwitterSearch_init() {
  var inst = this;
  this._deck = document.getElementById("twitter-search-deck");
  this._searchItemsBox = document.getElementById("search-term-specified");
  this._searchTerm = "";
  this._coopSearch = null;
  this._twitterSearchUrn = "";

  // Store the widgetId passed in as a parameter.
  var args = window.location.href.split("?");
  if (args[1]) {
    this._twitterSearchUrn = TWITTER_SEARCH_URN + ":" + args[1].split("=")[1];
    this._coopSearch = this._coop.get(this._twitterSearchUrn);
  }

  this._rdfObserver = {
    rdfChanged: function TwitterSearch_rdfChanged(ds,
                                                  type,
                                                  source,
                                                  predicate,
                                                  target,
                                                  oldtarget)
    {
      inst._logger.debug("rdfChanged()");
      if (!source) {
        inst._logger.debug("rdfChanged: source is nothing so exiting");
        return null;
      }
      var coopObj = inst._coop.get_from_resource(source);
      if (!coopObj) {
        inst._logger.debug("rdfChanged: coopObj is nothing so exiting");
        return null;
      }

      // Updates the widget elements after search refreshes.
      if (coopObj.isInstanceOf(inst._coop.TwitterSearch) &&
          inst._twitterSearchUrn == coopObj.id())
      {
        if (predicate.Value == "http://flock.com/rdf#isRefreshing") {
          if (coopObj.isRefreshing) {
            inst._logger.debug("rdfChanged: isRefreshing == true");
          } else {
            inst._logger.debug("rdfChanged: isRefreshing == false");
            gTwitterSearch.doLayout();
          }
        }
      }
    }
  };

  var observable = this._ds.QueryInterface(Ci.flockIRDFObservable);
  var refreshPredicate = "http://flock.com/rdf#isRefreshing";
  observable.addArcObserver(Ci.flockIRDFObserver.WATCH_TYPES,
                            null,
                            this._rdfSvc.GetResource(refreshPredicate),
                            null,
                            this._rdfObserver);

  if (this._coopSearch && this._coopSearch.searchTerm) {
    // Load previous search term.
    gTwitterSearch.enableSearch(this._coopSearch.searchTerm);
  } else {
    gTwitterSearch.doLayout();
  }
};

TwitterSearch.prototype.uninit =
function TwitterSearch_uninit() {
  if (this._coopSearch) {
    this._coopSearch.isPollable = false;
  }
  var observable = this._ds.QueryInterface(Ci.flockIRDFObservable);
  var refreshPredicate = "http://flock.com/rdf#isRefreshing";
  observable.removeArcObserver(Ci.flockIRDFObserver.WATCH_TYPES,
                               null,
                               this._rdfSvc.GetResource(refreshPredicate),
                               null,
                               this._rdfObserver);
};

TwitterSearch.prototype.doLayout =
function TwitterSearch_doLayout() {
  if (this._searchTerm) {
    this.clearSearchItems();

    var twitterSearchChildren = this._coopSearch.children;
    var childrenEnum = twitterSearchChildren.enumerate();

    if (childrenEnum.hasMoreElements()) {
      while (childrenEnum.hasMoreElements()) {
        this.insertSearchItem(childrenEnum.getNext());
      }
      this._deck.selectedIndex = DECK_RESULTS;
    } else {
      // No results found.
      this._deck.selectedIndex = DECK_NO_RESULTS;
    }
  } else {
    this.disableSearch();
    this._deck.selectedIndex = DECK_NO_SEARCH;
  }
};

TwitterSearch.prototype.clearSearchItems =
function TwitterSearch_clearSearchItems() {
  while (this._searchItemsBox.firstChild) {
    this._searchItemsBox.removeChild(this._searchItemsBox.firstChild);
  }
};

TwitterSearch.prototype.insertSearchItem =
function TwitterSearch_insertSearchItem(aSearchItem) {
  this._logger.debug("insertSearchItem()");
  var searchItem = document.createElement("friendfeeditem");
  // Use Flock snowman.
  var avatar = (aSearchItem.avatar == TWITTER_DEFAULT_AVATAR)
             ? FLOCK_SNOWMAN_URL
             : aSearchItem.avatar;
  searchItem.setAttribute("avatarUrl", avatar);
  searchItem.setAttribute("id", aSearchItem.id());
  searchItem.setAttribute("serviceId", TWITTERSEARCH_CONTRACT_ID);
  searchItem.setAttribute("faviconUrl", this._twitterSvc.icon);
  searchItem.setAttribute("tweetId", aSearchItem.itemId);
  searchItem.setAttribute("onclick", "event.stopPropagation(); return false;");
  searchItem.setAttribute("onmouseup",
                          "searchItemClicked(this, event); return false;");
  searchItem.setAttribute("ondraggesture",
                          "nsDragAndDrop.startDrag(event, draggingObserver, true);");
  searchItem.setAttribute("faviconOnClick", "faviconClicked(this, event);");
  searchItem.setAttribute("avatarOnClick", "avatarClicked(this, event);");
  var dt = aSearchItem.createDate;
  searchItem.setAttribute("timeInfo",
                          FlockDateFormatter.getFriendlyLastDate(dt));
  searchItem.setAttribute("fromUsername", aSearchItem.fromUsername);
  searchItem.handle = aSearchItem.fromUsername + ":";
  // Parse status for display. Responses from Twitter contain HTML entities.
  var status = flockXMLDecode(aSearchItem.itemText);
  searchItem.setAttribute("status", status);
  searchItem.description = this._twitterSvc.parseStatus(document, status);
  flockBreakLongText(searchItem.description, 40);
  // Only show reply button if there is an authenticated Twitter account.
  if (this.getAuthTwitterAccount()) {
    searchItem.setAttribute("reply_enabled", "true");
    searchItem.setAttribute("retweet_enabled", "true");
 }

  // Append search item.
  this._searchItemsBox.appendChild(searchItem);

  // Use pretty date for timestamp tooltip.
  var dateLbl = document.getAnonymousElementByAttribute(searchItem,
                                                        "anonid",
                                                        "person-lastupdate");
  dateLbl.setAttribute("tooltiptext", FlockDateFormatter.getDateTimeString(dt));

  var os = Cc["@mozilla.org/observer-service;1"]
           .getService(Ci.nsIObserverService);
  os.notifyObservers(null, "refresh-myworld-size", false);
};

TwitterSearch.prototype.enableSearch =
function TwitterSearch_enableSearch(aSearchTerm) {
  this._searchTerm = aSearchTerm;
  this._deck.selectedIndex = DECK_THROBBER;
  
  if (!this._coopSearch) {
    var refreshInterval =
      this._wd.getString(CLASS_SHORT_NAME, "twitterSearchRefreshInterval", "20");
    this._coopSearch = new this._coop.TwitterSearch(this._twitterSearchUrn, {
      serviceId: TWITTERSEARCH_CONTRACT_ID,
      refreshInterval: refreshInterval
    });
    this._coop.twitter_search_root.children.addOnce(this._coopSearch);
  }

  this._coopSearch.searchTerm = aSearchTerm;
  this._coopSearch.isPollable = true;
  // Trigger refresh.
  this._coopSearch.nextRefresh = new Date(0);
};

TwitterSearch.prototype.disableSearch =
function TwitterSearch_disableSearch() {
  this._searchTerm = "";
  this._deck.selectedIndex = DECK_NO_SEARCH;

  if (this._coopSearch) {
    this._coopSearch.searchTerm = "";
    this._coopSearch.isPollable = false;
  }

  this.clearSearchItems();
};

TwitterSearch.prototype.getAuthTwitterAccount =
function TwitterSearch_getAuthTwitterAccount() {
  return this._twitterSvc
             .getAccount(this._twitterSvc.getAuthenticatedAccount());
};

function loadURI(aURL, aEvent) {
  openURLMyWorld(aURL, aEvent);
  aEvent.stopPropagation();
}

function hoverURI(aLinkNode, aEvent) {
  function cb_setStatus(aStatus) {
    window.status = aStatus;
  }
  if (aLinkNode) {
    FlockURLUtils.hoverLink(aLinkNode, cb_setStatus);
  } else {
    cb_setStatus("");
  }
}

function searchItemClicked(aNode, aEvent) {
  var url = gTwitterSearch._wd
                          .getString(CLASS_SHORT_NAME, "tweetURL", "")
                          .replace("%username%",
                                   aNode.getAttribute("fromUsername"))
                          .replace("%tweetid%",
                                   aNode.getAttribute("tweetId"));
  loadURI(url, aEvent);
}

function faviconClicked(aNode, aEvent) {
  var url = gTwitterSearch._wd
                          .getLocalizedString(CLASS_SHORT_NAME,
                                              "homePageURL",
                                              "");
  loadURI(url, aEvent);
}

function avatarClicked(aNode, aEvent) {
  var userName = document.getBindingParent(aNode).getAttribute("fromUsername");
  var url = gTwitterSearch._wd
                          .getString(CLASS_SHORT_NAME, "avatarURL", "")
                          .replace("%username%", userName);
  loadURI(url, aEvent);
}

function activityClicked(aNode, aEvent) {
  // Suppress mouse right-click
  if (aEvent.button == 2) {
    return;
  }
  // Twitter reply in the sidebar unless power-user has set pref otherwise
  var friendfeeditem = document.getBindingParent(aNode);
  if (!FlockPrefsUtils.getBoolPref(DISABLE_TWITTER_SIDEBAR_REPLY_PREF)) {
    var tweetId = friendfeeditem.getAttribute("tweetId");
    var statusText = "@" + friendfeeditem.getAttribute("fromUsername") + " ";
    fillTwitterStatusEntry(tweetId, statusText, "TwitterSearchReplyClicked");
  } else {
    gTwitterSearch.getAuthTwitterAccount()
                  .friendAction("replyFromTwitterSearch",
                                null,
                                friendfeeditem.id);
  }

  gMetrics.report("MyWorldTwitterWidget-ReplyClick", null);
}

function retweetClicked(aNode, aEvent) {
  // Suppress mouse right-click
  if (aEvent.button == 2) {
    return;
  }
  var friendfeeditem = document.getBindingParent(aNode);
  var tweetId = friendfeeditem.getAttribute("tweetId");
  var statusText = friendfeeditem.getAttribute("status");
  // Check if this is already a re-tweet
  if (!statusText.match(/^rt\W*@/i)) {
    // If not, append re-tweet info
    statusText = "RT @" + friendfeeditem.getAttribute("fromUsername")
               + " " + statusText;
  }
  fillTwitterStatusEntry(tweetId, statusText, "TwitterSearchRetweetClicked");

  gMetrics.report("MyWorldTwitterWidget-RetweetClick", null);
}

function onLoad() {
  gTwitterSearch = new TwitterSearch();
  gTwitterSearch.init();
}

function onUnload() {
  gTwitterSearch.uninit();
  gTwitterSearch = null;
}
