"use strict";

angular.module('arethusa.comments').factory('CommentsRetriever', [
  'configurator',
  'idHandler',
  'state',
  function(configurator, idHandler, state) {
    var comments = { document: [] };
    var alreadyLoaded;

    function splitIdAndComment(comment) {
      var i = lastIndexOfHeaderSection(comment);
      var header = comment.slice(0, i - 1);
      var comm   = comment.slice(i);
      var regexp = new RegExp('^##(.*?)##');
      var match = regexp.exec(header);
      var ids   = match ? match[1] : null;
      return [ids, comm];
    }

    function lastIndexOfHeaderSection(comment) {
      var i = comment.indexOf('#!#\n\n');
      // Backwards compabitilty for comments that didn't
      // have the token strings attached
      return i === -1 ? comment.indexOf('##\n\n') + 4 : i + 5;
    }

    function WrappedComment(ids, comment) {
      this.ids = ids;
      this.comments = [comment];
    }

    function addComments(id, comment) {
      // We might be provided with document level comments, that come
      // without token identifiers.
      if (!id) return comments.document.push(comment);

      var sIdAndWIds = id.split('.');

      var sId  = sIdAndWIds[0];
      var wIds = arethusaUtil.map(sIdAndWIds[1].split(','), function(id) {
        return idHandler.getId(id);
      });

      var arr = arethusaUtil.getProperty(comments, sId);
      if (!arr) {
        arr = [];
        arethusaUtil.setProperty(comments, sId, arr);
      }

      var span = sameSpan(arr, wIds);
      if (span) {
        span.comments.push(comment);
      } else {
        // We unshift on purpose - we want newly added comments on runtime to
        // appear on top of the list.
        span = new WrappedComment(wIds, comment);
        arr.unshift(span);
      }
      return span;
    }

    function sameSpan(arr, ids) {
      var ret;
      for (var i = 0; i < arr.length; i++) {
        var span = arr[i];
        if (angular.equals(span.ids, ids)) {
          ret = span;
          break;
        }
      }
      return ret;
    }

    function parseComment(commentObj, i) {
      var comment = commentObj.comment;
      var extracted = splitIdAndComment(comment);
      commentObj.comment = extracted[1];
      return addComments(extracted[0], commentObj);
    }

    function parseComments(res) {
      angular.forEach(res, parseComment);
      sortComments();
    }

    function sortCommentsOfChunk(wrappedComments, sId) {
      comments[sId] = wrappedComments.sort(function(a, b) {
        return a.ids > b.ids;
      });
    }


    function sortComments() {
      angular.forEach(comments, sortCommentsOfChunk);
    }

    function addFakeIdsAndStrings(comment) {
      var sId = comment.sId;
      var ids = comment.ids;
      var sourceIds = arethusaUtil.map(ids, function(id) {
        return idHandler.formatId(id, '%w');
      });
      var fakeId = '##' + sId + '.' + sourceIds.join(',') + '##\n\n';
      var strings = '#!# ' + state.toTokenStrings(ids) + ' #!#\n\n';
      comment.comment = fakeId + strings + comment.comment;
    }

    // This is to satisfy the Perseids API for now, will later be
    // handled by Perseids itself.
    // Cf. http://github.com/PerseusDL/perseids_docs/issues/152
    function addReason(comment) {
      comment.reason = "general";
    }

    return function(conf) {
      var self = this;
      var resource = configurator.provideResource(conf.resource);

      this.getData = function(chunkId, callback) {
        if (alreadyLoaded) {
          callback(comments[chunkId]);
        } else {
          resource.get().then(function(res) {
            parseComments(res.data);
            callback(comments[chunkId]);
          });
          alreadyLoaded = true;
        }
      };

      this.saveData = function(comment, success, error) {
        addFakeIdsAndStrings(comment);
        addReason(comment);
        resource.save(comment).then(function(res) {
          success(parseComment(res.data));
        }, error);
      };

      this.docLevelComments = function() {
        return comments.document;
      };
    };
  }
]);

@@ -491,19 +491,14 @@
     
-var ids   =
+return
  mat
@@ -506,16 +506,17 @@
 h ? 
+%5B
 match%5B1%5D
  : n
@@ -515,40 +515,32 @@
 h%5B1%5D
+, comm%5D
  : 
+%5B
 null
-;%0A      return %5Bids
 , comm
+ent
 %5D;%0A 

Fix minor bug in commentsRetriever