/*!
 * Copyright 2009 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


var padsavedrevs = (function() {

  function reversedCopy(L) {
    var L2 = L.slice();
    L2.reverse();
    return L2;
  }

  function makeRevisionBox(revisionInfo, rnum) {
    var box = $('<div class="srouterbox">'+
                '<div class="srinnerbox">'+
                '<a href="javascript:void(0)" class="srname"><!-- --></a>'+
                '<div class="sractions"><a class="srview" href="javascript:void(0)" target="_blank">view</a> | <a class="srrestore" href="javascript:void(0)">restore</a></div>'+
                '<div class="srtime"><!-- --></div>'+
                '<div class="srauthor"><!-- --></div>'+
                '<img class="srtwirly" src="/static/img/status-ball.gif">'+
                '</div></div>');
    setBoxLabel(box, revisionInfo.label);
    setBoxTimestamp(box, revisionInfo.timestamp);
    box.find(".srauthor").text("by "+revisionInfo.savedBy);
    var viewLink = '/ep/pad/view/'+pad.getPadId()+'/'+revisionInfo.id;
    box.find(".srview").attr('href', viewLink);
    var restoreLink = 'javascript:void padsavedrevs.restoreRevision('+rnum+');';
    box.find(".srrestore").attr('href', restoreLink);
    box.find(".srname").click(function(evt) {
      editRevisionLabel(rnum, box);
    });
    return box;
  }
  function setBoxLabel(box, label) {
    box.find(".srname").text(label).attr('title', label);
  }
  function setBoxTimestamp(box, timestamp) {
    box.find(".srtime").text(
      padutils.timediff(new Date(timestamp)));
  }
  function getNthBox(n) {
    return $("#savedrevisions .srouterbox").eq(n);
  }
  function editRevisionLabel(rnum, box) {
    var input = $('<input type="text" class="srnameedit"/>');
    box.find(".srnameedit").remove(); // just in case
    var label = box.find(".srname");
    input.width(label.width());
    input.height(label.height());
    input.css('top', label.position().top);
    input.css('left', label.position().left);
    label.after(input);
    label.css('opacity', 0);
    function endEdit() {
      input.remove();
      label.css('opacity', 1);
    }
    var rev = currentRevisionList[rnum];
    var oldLabel = rev.label;
    input.blur(function() {
      var newLabel = input.val();
      if (newLabel && newLabel != oldLabel) {
        relabelRevision(rnum, newLabel);
      }
      endEdit();
    });
    input.val(rev.label).focus().select();
    padutils.bindEnterAndEscape(input, function onEnter() {
      input.blur();
    }, function onEscape() {
      input.val('').blur();
    });
  }
  function relabelRevision(rnum, newLabel) {
    var rev = currentRevisionList[rnum];
    $.ajax({
      type: 'post',
      url: '/ep/pad/saverevisionlabel',
      data: {userId: pad.getUserId(),
	     padId: pad.getPadId(),
	     revId: rev.id,
	     newLabel: newLabel},
      success: success,
      error: error
    });
    function success(text) {
      var newRevisionList = JSON.parse(text);
      self.newRevisionList(newRevisionList);
      pad.sendClientMessage({
        type: 'revisionLabel',
        revisionList: reversedCopy(currentRevisionList),
        savedBy: pad.getUserName(),
        newLabel: newLabel
      });
    }
    function error(e) {
      alert("Oops! There was an error saving that revision label.  Please try again later.");
    }
  }

  var currentRevisionList = [];
  function setRevisionList(newRevisionList, noAnimation) {
    // deals with changed labels and new added revisions
    for(var i=0; i<currentRevisionList.length; i++) {
      var a = currentRevisionList[i];
      var b = newRevisionList[i];
      if (b.label != a.label) {
        setBoxLabel(getNthBox(i), b.label);
      }
    }
    for(var j=currentRevisionList.length; j<newRevisionList.length; j++) {
      var newBox = makeRevisionBox(newRevisionList[j], j);
      $("#savedrevs-scrollinner").append(newBox);
      newBox.css('left', j * REVISION_BOX_WIDTH);
    }
    var newOnes = (newRevisionList.length > currentRevisionList.length);
    currentRevisionList = newRevisionList;
    if (newOnes) {
      setDesiredScroll(getMaxScroll());
      if (noAnimation) {
        setScroll(desiredScroll);
      }

      if (! noAnimation) {
        var nameOfLast = currentRevisionList[currentRevisionList.length-1].label;
        displaySavedTip(nameOfLast);
      }
    }
  }
  function refreshRevisionList() {
    for(var i=0;i<currentRevisionList.length; i++) {
      var r = currentRevisionList[i];
      var box = getNthBox(i);
      setBoxTimestamp(box, r.timestamp);
    }
  }

  var savedTipAnimator = padutils.makeShowHideAnimator(function(state) {
    if (state == -1) {
      $("#revision-notifier").css('opacity', 0).css('display', 'block');
    }
    else if (state == 0) {
      $("#revision-notifier").css('opacity', 1);
    }
    else if (state == 1) {
      $("#revision-notifier").css('opacity', 0).css('display', 'none');
    }
    else if (state < 0) {
      $("#revision-notifier").css('opacity', 1);
    }
    else if (state > 0) {
      $("#revision-notifier").css('opacity', 1 - state);
    }
  }, false, 25, 300);

  function displaySavedTip(text) {
    $("#revision-notifier .name").text(text);
    savedTipAnimator.show();
    padutils.cancelActions("hide-revision-notifier");
    var hideLater = padutils.getCancellableAction("hide-revision-notifier",
                                                  function() {
                                                    savedTipAnimator.hide();
                                                  });
    window.setTimeout(hideLater, 3000);
  }

  var REVISION_BOX_WIDTH = 120;
  var curScroll = 0; // distance between left of revisions and right of view
  var desiredScroll = 0;
  function getScrollWidth() {
    return REVISION_BOX_WIDTH * currentRevisionList.length;
  }
  function getViewportWidth() {
    return $("#savedrevs-scrollouter").width();
  }
  function getMinScroll() {
    return Math.min(getViewportWidth(), getScrollWidth());
  }
  function getMaxScroll() {
    return getScrollWidth();
  }
  function setScroll(newScroll) {
    curScroll = newScroll;
    $("#savedrevs-scrollinner").css('right', newScroll);
    updateScrollArrows();
  }
  function setDesiredScroll(newDesiredScroll, dontUpdate) {
    desiredScroll = Math.min(getMaxScroll(), Math.max(getMinScroll(),
                                                      newDesiredScroll));
    if (! dontUpdate) {
      updateScroll();
    }
  }
  function updateScroll() {
    updateScrollArrows();
    scrollAnimator.scheduleAnimation();
  }
  function updateScrollArrows() {
    $("#savedrevs-scrollleft").toggleClass("disabledscrollleft",
                                           desiredScroll <= getMinScroll());
    $("#savedrevs-scrollright").toggleClass("disabledscrollright",
                                           desiredScroll >= getMaxScroll());
  }
  var scrollAnimator = padutils.makeAnimationScheduler(function() {
    setDesiredScroll(desiredScroll, true); // re-clamp
    if (Math.abs(desiredScroll - curScroll) < 1) {
      setScroll(desiredScroll);
      return false;
    }
    else {
      setScroll(curScroll + (desiredScroll - curScroll)*0.5);
      return true;
    }
  }, 50, 2);

  var isSaving = false;
  function setIsSaving(v) {
    isSaving = v;
    rerenderButton();
  }

  function haveReachedRevLimit() {
    var mv = pad.getPrivilege('maxRevisions');
    return (!(mv < 0 || mv > currentRevisionList.length));
  }
  function rerenderButton() {
    if (isSaving || (! pad.isFullyConnected()) ||
        haveReachedRevLimit()) {
      $("#savedrevs-savenow").css('opacity', 0.75);
    }
    else {
      $("#savedrevs-savenow").css('opacity', 1);
    }
  }

  var scrollRepeatTimer = null;
  var scrollStartTime = 0;
  function setScrollRepeatTimer(dir) {
    clearScrollRepeatTimer();
    scrollStartTime = +new Date;
    scrollRepeatTimer = window.setTimeout(function f() {
      if (! scrollRepeatTimer) {
        return;
      }
      self.scroll(dir);
      var scrollTime = (+new Date) - scrollStartTime;
      var delay = (scrollTime > 2000 ? 50 : 300);
      scrollRepeatTimer = window.setTimeout(f, delay);
    }, 300);
    $(document).bind('mouseup', clearScrollRepeatTimer);
  }
  function clearScrollRepeatTimer() {
    if (scrollRepeatTimer) {
      window.clearTimeout(scrollRepeatTimer);
      scrollRepeatTimer = null;
    }
    $(document).unbind('mouseup', clearScrollRepeatTimer);
  }

  var self = {
    init: function(initialRevisions) {
      self.newRevisionList(initialRevisions, true);

      $("#savedrevs-savenow").click(function() { self.saveNow(); });
      $("#savedrevs-scrollleft").mousedown(function() {
        self.scroll('left');
        setScrollRepeatTimer('left');
      });
      $("#savedrevs-scrollright").mousedown(function() {
        self.scroll('right');
        setScrollRepeatTimer('right');
      });
      $("#savedrevs-close").click(function() {paddocbar.setShownPanel(null);});

      // update "saved n minutes ago" times
      window.setInterval(function() {
        refreshRevisionList();
      }, 60*1000);
    },
    restoreRevision: function(rnum) {
      var rev = currentRevisionList[rnum];
      var warning = ("Restoring this revision will overwrite the current"
		     + " text of the pad. "+
                     "Are you sure you want to continue?");
      var hidePanel = paddocbar.hideLaterIfNoOtherInteraction();
      var box = getNthBox(rnum);
      if (confirm(warning)) {
        box.find(".srtwirly").show();
        $.ajax({
          type: 'get',
          url: '/ep/pad/getrevisionatext',
          data: {padId: pad.getPadId(), revId: rev.id},
          success: success,
          error: error
        });
      }
      function success(resultJson) {
        untwirl();
        var result = JSON.parse(resultJson);
        padeditor.restoreRevisionText(result);
        window.setTimeout(function() {
          hidePanel();
        }, 0);
      }
      function error(e) {
        untwirl();
        alert("Oops!  There was an error retreiving the text (revNum= "+
	      rev.revNum+"; padId="+pad.getPadId());
      }
      function untwirl() {
        box.find(".srtwirly").hide();
      }
    },
    showReachedLimit: function() {
      alert("Sorry, you do not have privileges to save more than "+
            pad.getPrivilege('maxRevisions')+" revisions.");
    },
    newRevisionList: function(lst, noAnimation) {
      // server gives us list with newest first;
      // we want chronological order
      var L = reversedCopy(lst);
      setRevisionList(L, noAnimation);
      rerenderButton();
    },
    saveNow: function() {
      if (isSaving) {
        return;
      }
      if (! pad.isFullyConnected()) {
        return;
      }
      if (haveReachedRevLimit()) {
        self.showReachedLimit();
        return;
      }
      setIsSaving(true);
      var savedBy = pad.getUserName() || "unnamed";
      pad.callWhenNotCommitting(submitSave);

      function submitSave() {
        $.ajax({
          type: 'post',
          url: '/ep/pad/saverevision',
          data: {
	    padId: pad.getPadId(),
	    savedBy: savedBy,
	    savedById: pad.getUserId(),
	    revNum: pad.getCollabRevisionNumber()
          },
          success: success,
          error: error
        });
      }
      function success(text) {
        setIsSaving(false);
        var newRevisionList = JSON.parse(text);
        self.newRevisionList(newRevisionList);
        pad.sendClientMessage({
          type: 'newRevisionList',
          revisionList: newRevisionList,
          savedBy: savedBy
        });
      }
      function error(e) {
        setIsSaving(false);
        alert("Oops!  The server failed to save the revision.  Please try again later.");
      }
    },
    handleResizePage: function() {
      updateScrollArrows();
    },
    handleIsFullyConnected: function(isConnected) {
      rerenderButton();
    },
    scroll: function(dir) {
      var minScroll = getMinScroll();
      var maxScroll = getMaxScroll();
      if (dir == 'left') {
        if (desiredScroll > minScroll) {
          var n = Math.floor((desiredScroll - 1 - minScroll) /
                             REVISION_BOX_WIDTH);
          setDesiredScroll(Math.max(0, n)*REVISION_BOX_WIDTH + minScroll);
        }
      }
      else if (dir == 'right') {
        if (desiredScroll < maxScroll) {
          var n = Math.floor((maxScroll - desiredScroll - 1) /
                             REVISION_BOX_WIDTH);
          setDesiredScroll(maxScroll - Math.max(0, n)*REVISION_BOX_WIDTH);
        }
      }
    }
  };
  return self;
}());
