// 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

if (!Cc) const Cc = Components.classes;
if (!Ci) const Ci = Components.interfaces;

Components.utils.import("resource:///modules/FlockCastUtils.jsm");

const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

const CREDIT_REDIR = 'http://www.flock.com/blogged-with-flock';

const RECENT_POSTS_NUMBER = 25;
var gParams;
var gB;
var gPostListUpdated = false;
var gPostPermalink = "";
var gWebService;
var gAccount;
var gPublicationCancelled = false;

var gErrorCount = 0;
var gTimeout;

var gBlogService = Cc["@flock.com/flock-blog;1"].getService(Ci.flockIBlogService);

var faves_coop = Components.classes["@flock.com/singleton;1"]
                           .getService(Components.interfaces.flockISingleton)
                           .getSingleton("chrome://flock/content/common/load-faves-coop.js")
                           .wrappedJSObject;

function $(aId) {
  return document.getElementById(aId);
}

// nsISimpleEnumerator implementation
function simpleEnumerator (aArray) {
    aArray.hasMoreElements = function () { 
        return this.length != 0; 
    }
    aArray.getNext = function () { 
        return this.shift (); 
    }
    return aArray;
}

// nsIStringEnumerator implementation
function stringEnumerator (aArray) {
  aArray.hasMore = function () { 
    return this.length != 0; 
  }
  aArray.getNext = function () { 
    var rval = this.shift (); 
    return rval;
  }
  return aArray;
}

function createTags(aString) {
  // ''.split(',') returns [''], but we want []
  var tags = aString.replace(" ", "", "g");
  if (tags == '') {
    return stringEnumerator([]);
  } else {
    return stringEnumerator(tags.split(','));
  }
}

function categoryFactory(aId, aLabel) {
  this.id = aId;
  this.label = aLabel;
}

categoryFactory.prototype = {
  getInterfaces: function (count) {
    var interfaceList = [Components.interfaces.flockIBlogCategory, Components.interfaces.nsIClassInfo];
    count.value = interfaceList.length;
    return interfaceList;
  },
  QueryInterface: function (iid) {
    if (!iid.equals(Components.interfaces.flockIBlogCategory))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  },
  getHelperForLanguage: function (count) {return null;}
}


function setupBlog(aId) {
  gB = faves_coop.get(aId);
  try {
    gWebService = Cc[gB.getParent().serviceId].getService(Ci.flockIBlogWebService);
    gAccount = gWebService.getAccount(gB.getParent().id());
  } catch(e) {
    dump("*** ERROR: Couldn't create the component: "+gB.getParent().serviceId+"\n");
  }

  if (FlockCastUtils.isActive() &&
      FlockCastUtils.hasLoggedInFlockCastAccount())
  {
    $("flockcast-checkbox").setAttribute("checked", gB.publishStories);
  }

  // Enable categories if supported
  switch (gWebService.supportsCategories) {
    case Ci.flockIBlogWebService.CATEGORIES_NO:
      $('flock-blog-categories-container').setAttribute('collapsed', true);
      break;
    case Ci.flockIBlogWebService.CATEGORIES_SINGLE:
      $('flock-blog-categories-container').setAttribute('collapsed', false);
      $('flock-blog-categories').setAttribute('seltype', 'single');
      break;
    case Ci.flockIBlogWebService.CATEGORIES_MULTIPLE:
      $('flock-blog-categories-container').setAttribute('collapsed', false);
      $('flock-blog-categories').setAttribute('seltype', 'multiple');
      break;
  }
  if (gWebService.metadataOverlay && gWebService.metadataOverlay != "") {
    $('extra-attributes').setAttribute('src', gWebService.metadataOverlay);
    $('extra-attributes').setAttribute('collapsed', 'false');
    // set the right size
  } else {
    $('extra-attributes').setAttribute('collapsed', 'true');
  }

  // Enable post replace if supported
  $('flock-blog-newreplace').setAttribute('collapsed', !gWebService.supportsPostReplace);


  flock_blogEditorSetupCategories();
  if ((!refreshCategories.blogInProgress) &&
      (gWebService.supportsCategories != Ci.flockIBlogWebService.CATEGORIES_NO))
  {
    refreshCategories.exec();
  }
  // Update the post list if needed
  gPostListUpdated = false;
  if ($("radio-update").selected) {
    flock_blogUpdatePostList();
  }

  // DocumentViewerImpl::SizeToContent() has a bug that makes it impossible to
  // resize a dialog to a larger size if the contents expand. The reason is
  // that it makes a call to presContext->GetVisibleArea() which only returns
  // the size of the content that is not clipped, i.e. the currently
  // visible area.
  // The workaround is to manually resize the dialog to a best (slightly
  // oversize) guess, and then call sizeToContent() to finish the job.
  var dlgPaddingTop = 8;  // FIXME: Get this the proper way.
  var dlgPaddingBottom = 10;  // FIXME: Get this the proper way.
  window.innerHeight = $("metadata-deck").boxObject.height
                     + dlgPaddingTop
                     + dlgPaddingBottom;

  // Before resizing the window, wait to ensure all UI is loaded.
  setTimeout("window.sizeToContent();", 100);
}


function flock_blogMetadataLoad() {
  gParams  = window.arguments[0];

  if (FlockCastUtils.isActive()) {
    if (!FlockCastUtils.hasLoggedInFlockCastAccount()) {
      $("flockcast-checkbox").setAttribute("disabled", "true");
      $("flockcast-login-text").removeAttribute("hidden");
    }
  } else {
    $("flockcast-box").setAttribute("hidden", "true");
  }

  document.documentElement.getButton('cancel').parentNode.setAttribute('hidden', 'true');
  // TODO: switch to the default blog (not the first one)
  populatesBlogList();
  var accts = $("blog-account-selector");
  if(!accts.selectedItem)
    accts.selectedIndex = 0;

  setupBlog(accts.selectedItem.id);
  $("accept-button").focus();
}


function populatesBlogList() {
  var blogList = $("flock-blog-accounts-popup");
  while (blogList.firstChild) {
    blogList.removeChild(blogList.firstChild);
  }

  var c_accounts = faves_coop.accounts_root.children.enumerate();
  while (c_accounts.hasMoreElements()) {
    var c_account = c_accounts.getNext();
    var children = c_account.children.enumerate();
    while (children.hasMoreElements()) {
      var child = children.getNext();
      if (!child || !child.isInstanceOf(faves_coop.Blog)) {
        continue;
      }
      var item = document.createElementNS(XUL_NS, "menuitem");
      item.setAttribute("class", "menuitem-iconic");
      item.setAttribute("id", child.id());
      item.setAttribute("label", child.title);
      item.setAttribute("src", c_account.favicon);
      var setupBlog = "setupBlog('" + child.id().replace(/'/g, "\\'") + "');";
      item.setAttribute("oncommand", setupBlog);
      blogList.appendChild(item);
    }
  }

  var accts = $("blog-account-selector");
  var defaultBlogId = gBlogService.getDefaultBlog();
  if (defaultBlogId == "") {
    accts.selectedIndex = 0;
    defaultBlogId = accts.selectedItem.id;
    gBlogService.setDefaultBlog(defaultBlogId);
  }
  accts.selectedItem = $(defaultBlogId);
}


function flock_blogEditorSetupCategories() {
  var catList = $('flock-blog-categories');

  var enum_ = gB.categories.enumerate();
  while (catList.getRowCount() > 0)
    catList.removeItemAt(0);
  while (enum_.hasMoreElements()) {
    var category = enum_.getNext();
    catList.appendItem(category.name, category.categoryId);
  }
}

// Helper function to get the formatted string with the brand name
function _getFormattedStringWithBrand(aBundle, aKey) {
  var bundle = Cc["@mozilla.org/intl/stringbundle;1"]
               .getService(Ci.nsIStringBundleService)
               .createBundle("chrome://branding/locale/brand.properties");
  var brand = bundle.GetStringFromName("brandShortName");
  return aBundle.getFormattedString(aKey, [brand]);
}

function promptUsernamePassword(aBlogId) {
  var strbundle = document.getElementById("blogStringBundle");
  var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
          getService(Ci.nsIPromptService);

  var account = gBlogService.getAccount(aBlogId).wrappedJSObject;
  var coopAccount = faves_coop.get(aBlogId).getParent();

  var username = { value: account.username };
  var password = { value: account.password };

  var title = strbundle.getString("flock.blog.metadata.error.auth.title");
  var msg = _getFormattedStringWithBrand(strbundle,
                                         "flock.blog.metadata.error.auth");
  var result = prompts.promptUsernameAndPassword(window,
                                                 title,
                                                 msg,
                                                 username,
                                                 password,
                                                 null,
                                                 {
                                                   value: false
                                                 });

  if (username.value != account.username) {
    coopAccount.accountId = username.value;
  }
  if (password.value != account.password) {
    var acUtils = Cc["@flock.com/account-utils;1"].
      getService(Ci.flockIAccountUtils);
    acUtils.setPassword(coopAccount.id(), username.value, password.value);
    this.refreshCategories.exec();
  }

  return result;
}

var refreshCategories = {
  exec: function() {
    this.blogInProgress = gB;
    $("categories-throbber").setAttribute("hidden", "false");
    gWebService.getCategoryList(this, gB.id());
  },
  // Implement refresh listener
  onFault: function RC_onFault(aFault) {
    this.blogInProgress = null;
    $("categories-throbber").setAttribute("hidden", "true");
  },
  onResult: function RC_onResult(aResult) {
    var svc = Components.classes['@flock.com/flock-blog;1'].getService(Components.interfaces.flockIBlogService);
    while (aResult.hasMoreElements()) {
      category = aResult.getNext().QueryInterface(Components.interfaces.flockIBlogCategory);
      svc.addCategory(this.blogInProgress.id(), category.id, category.label);
    }
    flock_blogEditorSetupCategories();
    this.blogInProgress = null;
    $("categories-throbber").setAttribute("hidden", "true");
  },
  onError: function RC_onError(aError) {
    this.blogInProgress = null;
    $("categories-throbber").setAttribute("hidden", "true");

    var strbundle = document.getElementById("blogStringBundle");
    if (aError.errorCode == Ci.flockIError.BLOG_INVALID_AUTH) {
      if (promptUsernamePassword(gB.id())) {
        this.exec();
      }
    } else {
      var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"]
        .getService(Ci.nsIPromptService);
      var title = strbundle.getString("flock.blog.metadata.error");
      var msg = strbundle.getString("flock.blog.metadata.error.refreshingCategories")
                    + "\n" + aError.errorString;
      prompts.alert(window, title, msg);
    }
  },

  blogInProgress: null
}

function onCreditCheck(aEvent) {
  // Mozilla's persist attribute is persisting *attributes*. However,
  // it doesn't work correctly because checking/unchecking changes the
  // property and the attribute is not always in sync with the property.
  // We fix that here by force-syncing the attribute to the property.
  var creditFlock = document.getElementById("creditFlock");
  creditFlock.setAttribute("checked", creditFlock.checked);
}

function onRadioCheck(value){
  if (value == 1) {
    if (!gPostListUpdated)
      flock_blogUpdatePostList();
    $('blog-post-selector').setAttribute('disabled', 'false');
  } else {
    $('blog-post-selector').setAttribute('disabled', 'true');
  }
}

function flock_blogUpdatePostList(){
  gPostListUpdated = true;

  var strbundle = document.getElementById("blogStringBundle");
  // var selectedBlog = "urn:flock:blog:settings:" + $("blog-account-selector").selectedItem.value;
  var listener = new populatePostList(gB.id());
  $('blog-post-selector').removeAllItems();
  $('blog-post-selector').setAttribute('label', strbundle.getString("flock.blog.metadata.loadingPostList"));
  $('blog-post-selector').setAttribute('src', 'chrome://global/skin/throbber/Throbber-small.gif');

  gWebService.getRecentPosts(listener, gB.id(), RECENT_POSTS_NUMBER);
}

function populatePostList(selectedBlog, force_update) {
  this.selectedBlog = selectedBlog;
}

populatePostList.prototype = {
  onResult: function PPL_onResult(result) {
    var strbundle = document.getElementById("blogStringBundle");
    $('blog-post-selector').setAttribute('label', strbundle.getString("flock.blog.metadata.selectPost"));
    $('blog-post-selector').setAttribute('src', '');
    var posts = $('blog-post-selector');
    while (result.hasMoreElements()) {
      var post = result.getNext().QueryInterface(Ci.flockIBlogPost);
      var item = posts.appendItem(post.title, post.postid);
      item.post = post;
    }
  },

  onFault: function PPL_onFault(aError) {
    gPostListUpdated = false;
    tryAgain = false;
    var strbundle = document.getElementById("blogStringBundle");
    if (aError.errorCode == Ci.flockIError.BLOG_INVALID_AUTH) {
      if (promptUsernamePassword(gB.id())) {
        flock_blogUpdatePostList();
        tryAgain = true;
      }
    } else {
      var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"]
        .getService(Ci.nsIPromptService);

      var title = strbundle.getString("flock.blog.metadata.error");
      var msg = strbundle.getString("flock.blog.metadata.error.retrievingPost");
      msg += "\n\n";
      msg += "[" + aError.serviceErrorCode + "] " + aError.serviceErrorString;

      prompts.alert(window, title, msg);
    }
    if (!tryAgain) {
      $("blog-post-selector").setAttribute("src", "");
      $("blog-post-selector").setAttribute("disabled", "true");
      $("blog-post-selector").setAttribute("label",
                                           strbundle.getString("flock.blog.metadata.unavailable"));
      $("newreplace-radiogroup").selectedIndex = 0;
    }
  },
  onError: function PPL_onError(aError) {
    gPostListUpdated = false;
    var strbundle = document.getElementById("blogStringBundle");
    var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"]
      .getService(Ci.nsIPromptService);

    var title = strbundle.getString("flock.blog.metadata.error");
    var msg = strbundle.getString("flock.blog.metadata.error.retrievingPost");
    prompts.alert(window, title, msg);
  }
}

function blogCloseMetadata() {
  window.opener.published = true;
  window.opener.blogName = gB.title;
  window.opener.permalink = gPostPermalink;
  window.opener.account = gAccount;
  window.opener.publishFeedStory = gB.publishStories;

  if ($('view-on-your-blog').getAttribute('checked')){
    window.opener.blogURL = gB.URL;
  }
  $('cancel-button').click();
}

function getExtraParameters() {
  var result = new Array();

  var extra = $("extra-attributes").contentDocument.getElementById('extraData');
  if (!extra)
    return result;
  var rowsTag = extra.getElementsByTagName('rows')[0];
  var rows = rowsTag.getElementsByTagName('row');
  for (let i = 0; i < rows.length; i++) {
    result.push(rows[i].getAttribute('value'));
  }
  return stringEnumerator(result);
}


function metadataPublishPost() {
  var strbundle = document.getElementById("blogStringBundle");
  var creditEntity = strbundle.getString("flock.blog.metadata.credit");
  // Keep breadcrumbs credited to Flock for now; see bug 14702
  var creditProduct =
    strbundle.getFormattedString("flock.blog.metadata.credit.product",
                                 ["Flock"]);
  var creditLink = <a href={CREDIT_REDIR}
                      style="color: #999; font-weight: bold;"
                      target="_new"
                      title={creditProduct}>{creditProduct}</a>;
  var creditBlurb = creditEntity.replace("%1", creditLink.toXMLString());
  var flockCredit = '<div class="flockcredit" '
                  + 'style="text-align: right; color: #CCC; font-size: x-small;">'
                  + creditBlurb
                  + '</div>';
  var newPost = !($('radio-update').selected);
  var html = gParams.html;
  if ($('creditFlock').checked)
    html += flockCredit;

  if (!newPost && !($('blog-post-selector').selectedItem)) {
    var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                    .getService(Components.interfaces.nsIPromptService);
    var msg = strbundle.getString("flock.blog.metadata.selectToReplace");
    prompts.alert(window, strbundle.getString("flock.blog.metadata.missingInfo"), msg);
    return;
  }

  // Make sure the blog still exists
  if (!faves_coop.Blog.exists(gB.id())) {
    populatesBlogList();
    var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                    .getService(Components.interfaces.nsIPromptService);
    var msg = strbundle.getString("flock.blog.metadata.selectOther");
    prompts.alert(window, strbundle.getString("flock.blog.metadata.missingAccount"), msg);
    return;
  }

  var post = {};
  post.getInterfaces = function (count) {
    var interfaceList = [Components.interfaces['flockIBlogPost'], nsIClassInfo];
    count.value = interfaceList.length;
    return interfaceList;
  };
  post.QueryInterface = function (iid) {
    if (!iid.equals(Components.interfaces.flockIBlogPost))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  };

  if (!newPost){
    post  = $('blog-post-selector').selectedItem.post;
  }

  // window.success = false;

  post.title = gParams.title;
  post.description = html;
  post.tags = createTags(gParams.tags);
  post.extra = getExtraParameters();

  var params = {
    service: gWebService,
    blog: gB,
    post: post,
    newPost: newPost
  };

  $("metadata-deck").selectedIndex = 1;

  Cc["@flock.com/metrics-service;1"]
    .getService(Ci.flockIMetricsService)
    .report("BlogDialog-Publish", params.service.shortName);
  
  blogTriggerPublish(params.service, params.blog, params.post, params.newPost);
}

function blogTriggerPublish(service, blog, post, newPost) {
  window.gB = blog;
  // Clean the HTML
  // Livejournal doesn't like <br />
  if (post && post.html) {
    post.html = post.html.replace(/<br \/>/g, '<br/>');
  }
  var notifications = gBlogService.getNotifications();

  post.categories = flock_blogEditorGetCategoryArray();

  if(newPost) {
    var listener = BlogPublishListener;
    service.newPost(listener, blog.id(), post, true, notifications);
  } else {
    var listener = BlogEditListener;
    service.editPost(listener, blog.id(), post, true, notifications);
  }
}

function flock_blogEditorGetCategoryArray() {
  var rval = new Array();
  var categories = $("flock-blog-categories").selectedItems;
  for(var i=0; i<categories.length; ++i) {
    var categoryItem = categories[i];
    var cat = new categoryFactory(categoryItem.getAttribute("value"), categoryItem.getAttribute("label"));
    rval.push(cat);
  }
  return simpleEnumerator(rval);
}

var BlogPublishListener = {
  failCount: 0,
  onResult: function(aResult) {
    if (gPublicationCancelled) {
      // TODO: delete the published post
    } else {
      gBlogService.moveTo(gParams.draftId, gB.id());
      gPostPermalink = aResult;
      blogCloseMetadata();
    }
  },

  onFault: function (fault) {
    if (!gErrorCount || (gErrorCount < 2)) {
      gErrorCount = gErrorCount + 1;
      metadataPublishPost(); // Try again
    } else {
      var msg;
      window.clearTimeout(gTimeout);
      this.showErrorUI(fault.errorString);
    }
  },

  onError: function (error) {
    if (!gErrorCount || (gErrorCount < 2)) {
      gErrorCount = gErrorCount + 1;
      // Try again
      metadataPublishPost();
    } else {
      window.clearTimeout(gTimeout);
      this.showErrorUI(error.errorString);
    }
  },
    
  showErrorUI: function aMessage(aMsg) {
    try {
      $('metadata-deck').selectedIndex = 2;      
      $('publishing-error').firstChild.nodeValue = aMsg;
    } catch (ex) {
      dump (ex + '\n');
    }
  }
};

var BlogEditListener = {
  failCount: 0,
  onResult: function(result) {
    window.clearTimeout(gTimeout);
    gBlogService.moveTo(gParams.draftId, gB.id());
    if(result) {
      blogCloseMetadata();
    } else {
      $("metadata-deck").selectedIndex=0;
      blogCloseMetadata();
    }
  },

  onFault: function (fault) {
    if(this.failCount++<2) {
      metadataPublishPost(); // Try again
    } else {
      var msg;
      window.clearTimeout(gTimeout);
      alert(fault.errorString);
    }
  },

  onError: function (errorMsg) {
    var strbundle = document.getElementById("blogStringBundle");
    var msg = strbundle.getString("flock.blog.publishing.error");
    window.clearTimeout(gTimeout);
    alert(msg);
  }
};

function timeOutError() {
  var strbundle = document.getElementById("blogStringBundle");
  msg = strbundle.getString("flock.blog.publishing.timeError")+"\n";
  alert(msg);
  $('cancel-button').click();
};

function onWhatsThisClick() {
  var flockcast = document.getElementById("flockcast-box");
  if (!flockcast.hasAttribute("expanded")) {
    flockcast.setAttribute("expanded", "true");
    window.sizeToContent();

    var metrics = Cc["@flock.com/metrics-service;1"]
                  .getService(Ci.flockIMetricsService);
    metrics.report("FlockCast-Whats-This-Clicked", "blog");
  }
}
