<commit_before>/* Copyright 2013-2016 Extended Mind Technologies Oy
 *
 * 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.
 */

 /* global angular, jQuery */
 'use strict';

 function ConvertService($q, BackendClientService, ExtendedItemService, ItemLikeService,
                         ListsService, NotesService, TasksService) {

  function processTaskToNoteResponse(task, note, ownerUUID) {
    if (task.hist) note.hist = task.hist;
    NotesService.addNote(note, ownerUUID);
    TasksService.removeTask(task.trans.uuid, ownerUUID);
    var taskHistory = getTaskHistory(task);
    updateItemHistConvert(note, taskHistory, 'task', 'note', ownerUUID);
  }

  function processTaskToListResponse(task, list, ownerUUID) {
    if (task.hist) list.hist = task.hist;
    ListsService.addList(list, ownerUUID);
    TasksService.removeTask(task.trans.uuid, ownerUUID);

    var taskHistory = getTaskHistory(task);
    updateItemHistConvert(list, taskHistory, 'task', 'list', ownerUUID);
  }

  function processNoteToTaskResponse(note, task, ownerUUID) {
    if (note.hist) task.hist = note.hist;
    TasksService.addTask(task, ownerUUID);
    NotesService.removeNote(note.trans.uuid, ownerUUID);

    var noteHistory = getNoteHistory(note);
    updateItemHistConvert(task, noteHistory, 'note', 'task', ownerUUID);
  }

  function processNoteToListResponse(note, list, ownerUUID) {
    if (note.hist) list.hist = note.hist;
    ListsService.addList(list, ownerUUID);
    NotesService.removeNote(note.trans.uuid, ownerUUID);

    var noteHistory = getNoteHistory(note);
    updateItemHistConvert(list, noteHistory, 'note', 'list', ownerUUID);
  }

  function processListToTaskResponse(list, task, ownerUUID) {
    if (list.hist) task.hist = list.hist;
    TasksService.addTask(task, ownerUUID);
    ListsService.removeList(list.trans.uuid, ownerUUID);
    updateItemHistConvert(task, undefined, 'list', 'task', ownerUUID);
  }

  function processListToNoteResponse(list, note, ownerUUID) {
    if (list.hist) note.hist = list.hist;
    NotesService.addNote(note, ownerUUID);
    ListsService.removeList(list.trans.uuid, ownerUUID);
    updateItemHistConvert(note, undefined, 'list', 'note', ownerUUID);
  }

  function removeList(item) {
    if (item.trans.list) item.trans.list = undefined;
  }

  function getTaskHistory(task) {
    if (task.trans.due || task.trans.repeating || task.trans.reminders || task.trans.completed) {
      var taskHistory = {};
      if (task.trans.completed) taskHistory.completed = task.trans.completed;
      if (task.trans.due) taskHistory.due = task.trans.due;
      if (task.trans.repeating) taskHistory.repeating = task.trans.repeating;
      if (task.trans.reminders) taskHistory.reminders = task.trans.reminders;
      return taskHistory;
    }
  }

  function getNoteHistory(note) {
    if (note.trans.favorited) return {favorited: note.trans.favorited};
  }

  /**
   * @description Update convert object to item's history.
   *
   * Convert object stores item's history during session.
   *
   * @param {Object}  item          The item to copy to.
   * @param {Object}  convert       The object to copy to item.
   * @param {string}  fromItemType  Type of the item converted from
   * @param {string}  toItemType    Type of the item converted to
   */
   function updateItemHistConvert(item, fromHistory, fromItemType, toItemType, ownerUUID) {

    var hist = item.hist ? item.hist : {};
    // Delete existing 'toItemType' convert object because it may be out of sync
    var updated = false;
    if (hist.convert && hist.convert[toItemType]){
      delete hist.convert[toItemType];
      if (jQuery.isEmptyObject(hist.convert)){
        delete hist.convert;
        if (jQuery.isEmptyObject(hist)){
          hist = undefined;
        }else{
          hist.convert = undefined;
        }
      }
      updated = true;
    }
    // Check that history object is not empty
    if (fromHistory && Object.getOwnPropertyNames(fromHistory).length > 0) {
      if (!hist) hist = {};
      if (!hist.convert) hist.convert = {};
      hist.convert[fromItemType] = fromHistory;
      updated = true;
    }

    if (updated){
      if (toItemType === 'task'){
        TasksService.updateTaskHistProperties(item.trans.uuid, hist, ownerUUID);
      }else if (toItemType === 'note'){
        NotesService.updateNoteHistProperties(item.trans.uuid, hist, ownerUUID);
      }else if (toItemType === 'list'){
        ListsService.updateListHistProperties(item.trans.uuid, hist, ownerUUID);
      }
    }
  }

  function getNewItemSkeleton(item, timestamp){
    var newItem = {
      mod: {
        uuid: item.trans.uuid,
        title: item.trans.title,
        created: item.trans.created,
        modified: timestamp
      }
    };
    if (item.trans.link) newItem.mod.link = item.trans.link;
    if (item.mod && item.mod.hasOwnProperty('relationships')) {
      newItem.mod.relationships = item.mod.relationships;
    }
    else if (item.relationships) newItem.mod.relationships = item.relationships;
    return newItem;
  }

  function createNoteUsingHistConvert(item, timestamp){
    var note = getNewItemSkeleton(item, timestamp);
    if (item.trans.description) note.mod.content = item.trans.description;
    if (item.hist && item.hist.convert && item.hist.convert.note && item.hist.convert.note.favorited) {
      note.mod.favorited = item.hist.convert.note.favorited;
    }
    return note;
  }

  function createListUsingHistConvert(item, timestamp){
    var list = getNewItemSkeleton(item, timestamp);
    if (item.trans.content) list.mod.description = item.trans.content;
    else if (item.trans.description) list.mod.description = item.trans.description;
    return list;
  }

  function createTaskUsingHistConvert(item, timestamp){
    var task = getNewItemSkeleton(item, timestamp);
    if (item.trans.content) task.mod.description = item.trans.content;
    else if (item.trans.description) task.mod.description = item.trans.description;

    if (item.hist && item.hist.convert && item.hist.convert.task) {
      if (item.hist.convert.task.completed) task.mod.completed = item.hist.convert.task.completed;
      if (item.hist.convert.task.due) task.mod.due = item.hist.convert.task.due;
      if (item.hist.convert.task.repeating) task.mod.repeating = item.hist.convert.task.repeating;
      if (item.hist.convert.task.reminders) task.mod.reminders = item.hist.convert.task.reminders;
    }
    return task;
  }

  return {
    /*
    * PERSISTENT ITEM CONVERSION
    *
    * i.    verify that item to be converted exists
    * ii.   convert item to new type
    * iii.  remove old item from memory and add new item to memory
    */
    finishTaskToNoteConvert: function(task, ownerUUID) {
      var deferred = $q.defer();
      if (TasksService.getTaskStatus(task) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.hasTaskActiveReminder(task)) {
        deferred.reject({type: 'reminders'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/tasks/' + task.trans.uuid + '/convert_to_note';
        var transportTask = ItemLikeService.prepareTransport(task, 'task',
                                                             ownerUUID, TasksService.taskFieldInfos);
        var params = {
          type: 'task', owner: ownerUUID, uuid: task.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertTaskToNoteRegex,
                                         params, transportTask, fakeTimestamp);
        var note = createNoteUsingHistConvert(task, fakeTimestamp);
        processTaskToNoteResponse(task, note, ownerUUID);
        deferred.resolve(note);
      }
      return deferred.promise;
    },
    finishTaskToListConvert: function(task, ownerUUID) {
      var deferred = $q.defer();

      if (TasksService.getTaskStatus(task) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.hasTaskActiveReminder(task)) {
        deferred.reject({type: 'reminders'});
      } else {
        // NOTE: Currently only one-level lists are supported.
        // Remove pre-existing list before converting to list.
        removeList(task);
        var path = '/api/v2/owners/' + ownerUUID + '/data/tasks/' + task.trans.uuid + '/convert_to_list';
        var transportTask = ItemLikeService.prepareTransport(task, 'task',
                                                             ownerUUID, TasksService.taskFieldInfos);
        var params = {
          type: 'task', owner: ownerUUID, uuid: task.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertTaskToListRegex,
                                         params, transportTask, fakeTimestamp);
        var list = createListUsingHistConvert(task, fakeTimestamp);
        processTaskToListResponse(task, list, ownerUUID);
        deferred.resolve(list);
      }
      return deferred.promise;
    },
    finishNoteToTaskConvert: function(note, ownerUUID) {
      var deferred = $q.defer();

      if (NotesService.getNoteStatus(note) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/notes/' + note.trans.uuid + '/convert_to_task';
        var transportNote = ItemLikeService.prepareTransport(note, 'note',
                                                             ownerUUID, NotesService.noteFieldInfos);
        var params = {
          type: 'note', owner: ownerUUID, uuid: note.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertNoteToTaskRegex,
                                         params, transportNote, fakeTimestamp);
        var task = createTaskUsingHistConvert(note, fakeTimestamp);
        processNoteToTaskResponse(note, task, ownerUUID);
        deferred.resolve(task);
      }
      return deferred.promise;
    },
    finishNoteToListConvert: function(note, ownerUUID) {
      var deferred = $q.defer();
      if (NotesService.getNoteStatus(note) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else {
        // NOTE: Currently only one-level lists are supported.
        // Remove pre-existing list before convertin to list.
        removeList(note);

        var path = '/api/v2/owners/' + ownerUUID + '/data/notes/' + note.trans.uuid + '/convert_to_list';
        var transportNote = ItemLikeService.prepareTransport(note, 'note',
                                                             ownerUUID, NotesService.noteFieldInfos);
        var params = {
          type: 'note', owner: ownerUUID, uuid: note.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertNoteToListRegex,
                                         params, transportNote, fakeTimestamp);
        var list = createListUsingHistConvert(note, fakeTimestamp);
        processNoteToListResponse(note, list, ownerUUID);
        deferred.resolve(list);
      }
      return deferred.promise;
    },
    finishListToTaskConvert: function(list, ownerUUID) {
      var deferred = $q.defer();
      if (ListsService.getListStatus(list) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.isTasksWithList(list) ||
                 NotesService.isNotesWithList(list))
      {
        deferred.reject({type: 'parent'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/lists/' + list.trans.uuid + '/convert_to_task';
        var transportList = ItemLikeService.prepareTransport(list, 'list',
                                                             ownerUUID, ListsService.listFieldInfos);
        var params = {
          type: 'list', owner: ownerUUID, uuid: list.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertListToTaskRegex,
                                         params, transportList, fakeTimestamp);
        var task = createTaskUsingHistConvert(list, fakeTimestamp);
        processListToTaskResponse(list, task, ownerUUID);
        deferred.resolve(task);
      }
      return deferred.promise;
    },
    finishListToNoteConvert: function(list, ownerUUID) {
      var deferred = $q.defer();
      if (ListsService.getListStatus(list) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.isTasksWithList(list) ||
                 NotesService.isNotesWithList(list))
      {
        deferred.reject({type: 'parent'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/lists/' + list.trans.uuid + '/convert_to_note';
        var transportList = ItemLikeService.prepareTransport(list, 'list',
                                                             ownerUUID, ListsService.listFieldInfos);
        var params = {
          type: 'list', owner: ownerUUID, uuid: list.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertListToNoteRegex,
                                         params, transportList, fakeTimestamp);
        var note = createNoteUsingHistConvert(list, fakeTimestamp);
        processListToNoteResponse(list, note, ownerUUID);
        deferred.resolve(note);
      }
      return deferred.promise;
    },
    convertTaskToNoteRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/tasks/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_note$'),

    convertTaskToListRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/tasks/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_list$'),

    convertNoteToTaskRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/notes/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_task$'),

    convertNoteToListRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/notes/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_list$'),

    convertListToTaskRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/lists/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_task$'),
    convertListToNoteRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/lists/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_note$'),
  };
}
ConvertService['$inject'] = ['$q', 'BackendClientService', 'ExtendedItemService', 'ItemLikeService',
'ListsService', 'NotesService', 'TasksService'];
angular.module('em.main').factory('ConvertService', ConvertService);
<commit_msg>Fixed closure compiler problem<commit_after>/* Copyright 2013-2016 Extended Mind Technologies Oy
 *
 * 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.
 */

 /* global angular, jQuery */
 'use strict';

 function ConvertService($q, BackendClientService, ExtendedItemService, ItemLikeService,
                         ListsService, NotesService, TasksService) {

  function processTaskToNoteResponse(task, note, ownerUUID) {
    if (task.hist) note.hist = task.hist;
    NotesService.addNote(note, ownerUUID);
    TasksService.removeTask(task.trans.uuid, ownerUUID);
    var taskHistory = getTaskHistory(task);
    updateItemHistConvert(note, taskHistory, 'task', 'note', ownerUUID);
  }

  function processTaskToListResponse(task, list, ownerUUID) {
    if (task.hist) list.hist = task.hist;
    ListsService.addList(list, ownerUUID);
    TasksService.removeTask(task.trans.uuid, ownerUUID);

    var taskHistory = getTaskHistory(task);
    updateItemHistConvert(list, taskHistory, 'task', 'list', ownerUUID);
  }

  function processNoteToTaskResponse(note, task, ownerUUID) {
    if (note.hist) task.hist = note.hist;
    TasksService.addTask(task, ownerUUID);
    NotesService.removeNote(note.trans.uuid, ownerUUID);

    var noteHistory = getNoteHistory(note);
    updateItemHistConvert(task, noteHistory, 'note', 'task', ownerUUID);
  }

  function processNoteToListResponse(note, list, ownerUUID) {
    if (note.hist) list.hist = note.hist;
    ListsService.addList(list, ownerUUID);
    NotesService.removeNote(note.trans.uuid, ownerUUID);

    var noteHistory = getNoteHistory(note);
    updateItemHistConvert(list, noteHistory, 'note', 'list', ownerUUID);
  }

  function processListToTaskResponse(list, task, ownerUUID) {
    if (list.hist) task.hist = list.hist;
    TasksService.addTask(task, ownerUUID);
    ListsService.removeList(list.trans.uuid, ownerUUID);
    updateItemHistConvert(task, undefined, 'list', 'task', ownerUUID);
  }

  function processListToNoteResponse(list, note, ownerUUID) {
    if (list.hist) note.hist = list.hist;
    NotesService.addNote(note, ownerUUID);
    ListsService.removeList(list.trans.uuid, ownerUUID);
    updateItemHistConvert(note, undefined, 'list', 'note', ownerUUID);
  }

  function removeList(item) {
    if (item.trans.list) item.trans.list = undefined;
  }

  function getTaskHistory(task) {
    if (task.trans.due || task.trans.repeating || task.trans.reminders || task.trans.completed) {
      var taskHistory = {};
      if (task.trans.completed) taskHistory.completed = task.trans.completed;
      if (task.trans.due) taskHistory.due = task.trans.due;
      if (task.trans.repeating) taskHistory.repeating = task.trans.repeating;
      if (task.trans.reminders) taskHistory.reminders = task.trans.reminders;
      return taskHistory;
    }
  }

  function getNoteHistory(note) {
    if (note.trans.favorited) return {favorited: note.trans.favorited};
  }

  /**
   * @description Update convert object to item's history.
   *
   * Convert object stores item's history during session.
   *
   * @param {Object}  item          The item to copy to.
   * @param {Object}  convert       The object to copy to item.
   * @param {string}  fromItemType  Type of the item converted from
   * @param {string}  toItemType    Type of the item converted to
   */
   function updateItemHistConvert(item, fromHistory, fromItemType, toItemType, ownerUUID) {

    var hist = item.hist ? item.hist : {};
    // Delete existing 'toItemType' convert object because it may be out of sync
    var updated = false;
    if (hist.convert && hist.convert[toItemType]){
      delete hist.convert[toItemType];
      if (jQuery.isEmptyObject(hist.convert)){
        delete hist.convert;
        if (jQuery.isEmptyObject(hist)){
          hist = undefined;
        }else{
          hist.convert = undefined;
        }
      }
      updated = true;
    }
    // Check that history object is not empty
    if (fromHistory && Object.getOwnPropertyNames(fromHistory).length > 0) {
      if (!hist) hist = {};
      if (!hist.convert) hist.convert = {};
      hist.convert[fromItemType] = fromHistory;
      updated = true;
    }

    if (updated){
      if (toItemType === 'task'){
        TasksService.updateTaskHistProperties(item.trans.uuid, hist, ownerUUID);
      }else if (toItemType === 'note'){
        NotesService.updateNoteHistProperties(item.trans.uuid, hist, ownerUUID);
      }else if (toItemType === 'list'){
        ListsService.updateListHistProperties(item.trans.uuid, hist, ownerUUID);
      }
    }
  }

  function getNewItemSkeleton(item, timestamp){
    var newItem = {
      mod: {
        uuid: item.trans.uuid,
        title: item.trans.title,
        created: item.trans.created,
        modified: timestamp
      }
    };
    if (item.trans.link) newItem.mod.link = item.trans.link;
    if (item.mod && item.mod.hasOwnProperty('relationships')) {
      newItem.mod.relationships = item.mod.relationships;
    }
    else if (item.relationships) newItem.mod.relationships = item.relationships;
    return newItem;
  }

  function createNoteUsingHistConvert(item, timestamp){
    var note = getNewItemSkeleton(item, timestamp);
    if (item.trans.description) note.mod.content = item.trans.description;
    if (item.hist && item.hist.convert && item.hist.convert.note && item.hist.convert.note.favorited) {
      note.mod.favorited = item.hist.convert.note.favorited;
    }
    return note;
  }

  function createListUsingHistConvert(item, timestamp){
    var list = getNewItemSkeleton(item, timestamp);
    if (item.trans.content) list.mod.description = item.trans.content;
    else if (item.trans.description) list.mod.description = item.trans.description;
    return list;
  }

  function createTaskUsingHistConvert(item, timestamp){
    var task = getNewItemSkeleton(item, timestamp);
    if (item.trans.content) task.mod.description = item.trans.content;
    else if (item.trans.description) task.mod.description = item.trans.description;

    if (item.hist && item.hist.convert && item.hist.convert.task) {
      if (item.hist.convert.task.completed) task.mod.completed = item.hist.convert.task.completed;
      if (item.hist.convert.task.due) task.mod.due = item.hist.convert.task.due;
      if (item.hist.convert.task.repeating) task.mod.repeating = item.hist.convert.task.repeating;
      if (item.hist.convert.task.reminders) task.mod.reminders = item.hist.convert.task.reminders;
    }
    return task;
  }

  return {
    /*
    * PERSISTENT ITEM CONVERSION
    *
    * i.    verify that item to be converted exists
    * ii.   convert item to new type
    * iii.  remove old item from memory and add new item to memory
    */
    finishTaskToNoteConvert: function(task, ownerUUID) {
      var deferred = $q.defer();
      if (TasksService.getTaskStatus(task) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.hasTaskActiveReminder(task)) {
        deferred.reject({type: 'reminders'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/tasks/' + task.trans.uuid + '/convert_to_note';
        var transportTask = ItemLikeService.prepareTransport(task, 'task',
                                                             ownerUUID, TasksService.taskFieldInfos);
        var params = {
          type: 'task', owner: ownerUUID, uuid: task.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertTaskToNoteRegex,
                                         params, transportTask, fakeTimestamp);
        var note = createNoteUsingHistConvert(task, fakeTimestamp);
        processTaskToNoteResponse(task, note, ownerUUID);
        deferred.resolve(note);
      }
      return deferred.promise;
    },
    finishTaskToListConvert: function(task, ownerUUID) {
      var deferred = $q.defer();

      if (TasksService.getTaskStatus(task) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.hasTaskActiveReminder(task)) {
        deferred.reject({type: 'reminders'});
      } else {
        // NOTE: Currently only one-level lists are supported.
        // Remove pre-existing list before converting to list.
        removeList(task);
        var path = '/api/v2/owners/' + ownerUUID + '/data/tasks/' + task.trans.uuid + '/convert_to_list';
        var transportTask = ItemLikeService.prepareTransport(task, 'task',
                                                             ownerUUID, TasksService.taskFieldInfos);
        var params = {
          type: 'task', owner: ownerUUID, uuid: task.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertTaskToListRegex,
                                         params, transportTask, fakeTimestamp);
        var list = createListUsingHistConvert(task, fakeTimestamp);
        processTaskToListResponse(task, list, ownerUUID);
        deferred.resolve(list);
      }
      return deferred.promise;
    },
    finishNoteToTaskConvert: function(note, ownerUUID) {
      var deferred = $q.defer();

      if (NotesService.getNoteStatus(note) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/notes/' + note.trans.uuid + '/convert_to_task';
        var transportNote = ItemLikeService.prepareTransport(note, 'note',
                                                             ownerUUID, NotesService.noteFieldInfos);
        var params = {
          type: 'note', owner: ownerUUID, uuid: note.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertNoteToTaskRegex,
                                         params, transportNote, fakeTimestamp);
        var task = createTaskUsingHistConvert(note, fakeTimestamp);
        processNoteToTaskResponse(note, task, ownerUUID);
        deferred.resolve(task);
      }
      return deferred.promise;
    },
    finishNoteToListConvert: function(note, ownerUUID) {
      var deferred = $q.defer();
      if (NotesService.getNoteStatus(note) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else {
        // NOTE: Currently only one-level lists are supported.
        // Remove pre-existing list before convertin to list.
        removeList(note);

        var path = '/api/v2/owners/' + ownerUUID + '/data/notes/' + note.trans.uuid + '/convert_to_list';
        var transportNote = ItemLikeService.prepareTransport(note, 'note',
                                                             ownerUUID, NotesService.noteFieldInfos);
        var params = {
          type: 'note', owner: ownerUUID, uuid: note.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertNoteToListRegex,
                                         params, transportNote, fakeTimestamp);
        var list = createListUsingHistConvert(note, fakeTimestamp);
        processNoteToListResponse(note, list, ownerUUID);
        deferred.resolve(list);
      }
      return deferred.promise;
    },
    finishListToTaskConvert: function(list, ownerUUID) {
      var deferred = $q.defer();
      if (ListsService.getListStatus(list) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.isTasksWithList(list) ||
                 NotesService.isNotesWithList(list))
      {
        deferred.reject({type: 'parent'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/lists/' + list.trans.uuid + '/convert_to_task';
        var transportList = ItemLikeService.prepareTransport(list, 'list',
                                                             ownerUUID, ListsService.listFieldInfos);
        var params = {
          type: 'list', owner: ownerUUID, uuid: list.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertListToTaskRegex,
                                         params, transportList, fakeTimestamp);
        var task = createTaskUsingHistConvert(list, fakeTimestamp);
        processListToTaskResponse(list, task, ownerUUID);
        deferred.resolve(task);
      }
      return deferred.promise;
    },
    finishListToNoteConvert: function(list, ownerUUID) {
      var deferred = $q.defer();
      if (ListsService.getListStatus(list) === 'deleted') {
        deferred.reject({type: 'deleted'});
      } else if (TasksService.isTasksWithList(list) ||
                 NotesService.isNotesWithList(list))
      {
        deferred.reject({type: 'parent'});
      } else {
        var path = '/api/v2/owners/' + ownerUUID + '/data/lists/' + list.trans.uuid + '/convert_to_note';
        var transportList = ItemLikeService.prepareTransport(list, 'list',
                                                             ownerUUID, ListsService.listFieldInfos);
        var params = {
          type: 'list', owner: ownerUUID, uuid: list.trans.uuid, lastReplaceable: false
        };
        var fakeTimestamp = BackendClientService.generateFakeTimestamp();
        BackendClientService.postOffline(path, this.convertListToNoteRegex,
                                         params, transportList, fakeTimestamp);
        var note = createNoteUsingHistConvert(list, fakeTimestamp);
        processListToNoteResponse(list, note, ownerUUID);
        deferred.resolve(note);
      }
      return deferred.promise;
    },
    convertTaskToNoteRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/tasks/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_note$'),

    convertTaskToListRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/tasks/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_list$'),

    convertNoteToTaskRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/notes/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_task$'),

    convertNoteToListRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/notes/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_list$'),

    convertListToTaskRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/lists/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_task$'),
    convertListToNoteRegex: new RegExp('^' +
                                       BackendClientService.apiv2PrefixRegex.source +
                                       '/owners/' +
                                       BackendClientService.uuidRegex.source +
                                       '/data/lists/' +
                                       BackendClientService.uuidRegex.source +
                                       '/convert_to_note$')
  };
}
ConvertService['$inject'] = ['$q', 'BackendClientService', 'ExtendedItemService', 'ItemLikeService',
'ListsService', 'NotesService', 'TasksService'];
angular.module('em.main').factory('ConvertService', ConvertService);
<|endoftext|>


<commit_before>/* jshint browser: true, jquery: true */
/* global Panel:false, console:false, server:false, addWidget:false */

function addPanel(panel) {
  sendAddPanel(panel);
}

function updatePanel(panel) {
  sendUpdatePanel(panel);
}

function processPanelMessages(server, id, content) {
  var processed = false;

  switch (id) {
    case Panel.MESSAGE_PANELS:
      receivedPanels(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_ADD_PANEL:
      receivedAddPanel(server, new Panel(content));
      processed = true;
      break;

    case Panel.MESSAGE_DELETE_PANEL:
      receivedDeletePanel(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_UPDATE_PANEL:
      receivedUpdatePanel(server, new Panel(content));
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_UP:
      console.log("content: " + content);
      receivedMovePanelUp(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_DOWN:
      receivedMovePanelDown(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_LEFT:
      receivedMovePanelLeft(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_RIGHT:
      receivedMovePanelRight(server, content);
      processed = true;
      break;
  }

  return processed;
}

function isPanelAddMode() {
  // TODO: addPanelMode is global (refer main.js), not really happy about this
  return addPanelMode;
}

function receivedAddPanel(server, d) {
  addPanelToDom(d, isPanelAddMode());
  panelDragAndDrop.apply();
}

function receivedDeletePanel(server, id) {
  deletePanel(id);
}

function receivedMovePanelUp(server, id) {
  movePanelUp(id);
}

function receivedMovePanelDown(server, id) {
  movePanelDown(id);
}

function receivedMovePanelLeft(server, panel) {
  changePanelColumn(panel);
}

function receivedMovePanelRight(server, panel) {
  changePanelColumn(panel);
}

function receivedUpdatePanel(server, panel) {
  // get current data
  var currentPanelElement = $('#panel' + panel.id);

  var currentPanel = new Panel(currentPanelElement.data());

  // apply changes to DOM
  if(currentPanel.name !== panel.name) {
    $('#panelName' + panel.id).text(panel.name);
    currentPanelElement.data('name', panel.name);
  }

// ignore this for now, presume that only via move left/right that this can happen
//  if(currentPanel.column !== panel.column) {
//
//  }

  if(currentPanel.iconName !== panel.iconName) {
    $('#panelIcon' + panel.id).removeClass(currentPanel.iconName).addClass(panel.iconName);
    currentPanelElement.data('icon-name', panel.iconName);
  }
}

function receivedPanels(server, d) {
  // TODO: logic to handle resend of panels
  // $(".panelRow").remove();

  var buttonsVisible = isPanelAddMode();

  var panelsArray = [];

  for (var item in d) {
   panelsArray.push(new Panel(d[item]));
  }

  panelsArray.sort(function (a, b) {
      if (a.row  b.row) {
          return 1;
      }
      return 0;
  });

  panelsArray.forEach(function (p) {
    addPanelToDom(p, buttonsVisible);
  });

  panelDragAndDrop.apply();
}

function sendAddPanel(panel) {
  server.sendMessage(Panel.MESSAGE_ADD_PANEL, panel);
}

function sendDeletePanel(id) {
  server.sendMessage(Panel.MESSAGE_DELETE_PANEL, id);
}

function sendUpdatePanel(panel) {
  server.sendMessage(Panel.MESSAGE_UPDATE_PANEL, panel);
}

function sendMovePanelUp(id) {
  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_UP, id);
}

function sendMovePanelDown(id) {
  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_DOWN, id);
}

function sendMovePanelLeft(id) {
  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_LEFT, id);
}

function sendMovePanelRight(id) {
  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_RIGHT, id);
}

function addPanelToDom(panel, buttonsVisible) {
  var displayButtonClass = buttonsVisible ? "displayButton" : "";
  var displayStyle = buttonsVisible ? "block" : "none";

  //$("#columnContainer" + panel.column).append(
  $("#column" + panel.column).append(
    '
' +
    '
' +
    '
' +
    '        <button id="panelBtnAddWidget' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '        <button id="panelBtnRemoveWidget' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '        <button id="panelBtnDelete' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '        <button id="panelBtnMoveDown' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '        <button id="panelBtnMoveUp' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '        <button id="panelBtnMoveLeft' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '        <button id="panelBtnMoveRight' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '        <button id="panelBtnModify' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '
' +
    '     ' + panel.name + '' +
    '
' +
    '
' +
    '
' +
    '
'
  );

  $('#panel' + panel.id).hide().fadeIn('slow');

  $('#panelBtnAddWidget' + panel.id).on('click', function() {
    viewWidgetWizard('add', {}, panel.id);
  });

  $('#panelBtnRemoveWidget' + panel.id).on('click', function() {
  });

  $('#panelBtnDelete' + panel.id).on('click', function() {
    sendDeletePanel(panel.id);
  });

  $('#panelBtnMoveDown' + panel.id).on('click', function() {
    sendMovePanelDown(panel.id);
  });

  $('#panelBtnMoveUp' + panel.id).on('click', function() {
    sendMovePanelUp(panel.id);
  });

  $('#panelBtnMoveLeft' + panel.id).on('click', function() {
    sendMovePanelLeft(panel.id);
  });

  $('#panelBtnMoveRight' + panel.id).on('click', function() {
    sendMovePanelRight(panel.id);
  });

  $('#panelBtnModify' + panel.id).on('click', function() {
    displayPanelDialog('update', panel);
  });
}

function deletePanel(id) {
  $('#panel' + id)
    .animate({height: 0, padding: 0, margin: 0}, {easing: "linear", duration: "slow", queue: false})
    .fadeOut('slow', function() {
    this.remove();
  });
}

function movePanelDown(id) {
  var panelList = getPanelList(id);

  if(panelList['panel' + id].position < (Object.keys(panelList).length - 1)) {
    // move down
    swapPanelVertically(panelList['panel' + id].id, panelList['panel' + id].nextId);
  }
}

function movePanelUp(id) {
  var panelList = getPanelList(id);

  if(panelList['panel' + id].position > 0) {
    // move up
    swapPanelVertically(panelList['panel' + id].id, panelList['panel' + id].prevId);
  }
}

function changePanelColumn(panelData) {
  var panel = $('#panel' + panelData.id);

  $('#panel' + panelData.id)
    .animate({height: 0, padding: 0, margin: 0}, {easing: "linear", duration: "fast", queue: false})
    .fadeOut('fast', function() {
      panel
        .appendTo("#columnContainer" + panelData.column)
        .hide()
        .css('height', '')
        .css('padding', '')
        .css('margin', '')
        .fadeIn('fast');

  });
}

function getPanelList(id) {
  var prevPanel = null;
  var nextPanel = null;
  var counter = 0;
  var panelList = {};

  $('#panel' + id).parent().children().each(function() {
    panelList[$(this).attr('id')] = {
      id: $(this).attr('id'),
      position: counter++,
      value: this,
      prevId: null,
      nextId: null
    };

    if(prevPanel !== null) {
      panelList[$(this).attr('id')].prevId = prevPanel.id;
      prevPanel.nextId = $(this).attr('id');
    }

    prevPanel = panelList[$(this).attr('id')];
  });

  return panelList;
}

function swapPanelVertically(a, b){
    a = $('#' + a)[0];
    b = $('#' + b)[0];

    var t = a.parentNode.insertBefore(document.createTextNode(''), a);

    b.parentNode.insertBefore(a, b);
    t.parentNode.insertBefore(b, t);
    t.parentNode.removeChild(t);
}

<commit_msg>Temp removal of buttons replaced by DnD<commit_after>/* jshint browser: true, jquery: true */
/* global Panel:false, console:false, server:false, addWidget:false */

function addPanel(panel) {
  sendAddPanel(panel);
}

function updatePanel(panel) {
  sendUpdatePanel(panel);
}

function processPanelMessages(server, id, content) {
  var processed = false;

  switch (id) {
    case Panel.MESSAGE_PANELS:
      receivedPanels(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_ADD_PANEL:
      receivedAddPanel(server, new Panel(content));
      processed = true;
      break;

    case Panel.MESSAGE_DELETE_PANEL:
      receivedDeletePanel(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_UPDATE_PANEL:
      receivedUpdatePanel(server, new Panel(content));
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_UP:
      console.log("content: " + content);
      receivedMovePanelUp(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_DOWN:
      receivedMovePanelDown(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_LEFT:
      receivedMovePanelLeft(server, content);
      processed = true;
      break;

    case Panel.MESSAGE_MOVE_PANEL_RIGHT:
      receivedMovePanelRight(server, content);
      processed = true;
      break;
  }

  return processed;
}

function isPanelAddMode() {
  // TODO: addPanelMode is global (refer main.js), not really happy about this
  return addPanelMode;
}

function receivedAddPanel(server, d) {
  addPanelToDom(d, isPanelAddMode());
  panelDragAndDrop.apply();
}

function receivedDeletePanel(server, id) {
  deletePanel(id);
}

function receivedMovePanelUp(server, id) {
  movePanelUp(id);
}

function receivedMovePanelDown(server, id) {
  movePanelDown(id);
}

function receivedMovePanelLeft(server, panel) {
  changePanelColumn(panel);
}

function receivedMovePanelRight(server, panel) {
  changePanelColumn(panel);
}

function receivedUpdatePanel(server, panel) {
  // get current data
  var currentPanelElement = $('#panel' + panel.id);

  var currentPanel = new Panel(currentPanelElement.data());

  // apply changes to DOM
  if(currentPanel.name !== panel.name) {
    $('#panelName' + panel.id).text(panel.name);
    currentPanelElement.data('name', panel.name);
  }

// ignore this for now, presume that only via move left/right that this can happen
//  if(currentPanel.column !== panel.column) {
//
//  }

  if(currentPanel.iconName !== panel.iconName) {
    $('#panelIcon' + panel.id).removeClass(currentPanel.iconName).addClass(panel.iconName);
    currentPanelElement.data('icon-name', panel.iconName);
  }
}

function receivedPanels(server, d) {
  // TODO: logic to handle resend of panels
  // $(".panelRow").remove();

  var buttonsVisible = isPanelAddMode();

  var panelsArray = [];

  for (var item in d) {
   panelsArray.push(new Panel(d[item]));
  }

  panelsArray.sort(function (a, b) {
      if (a.row  b.row) {
          return 1;
      }
      return 0;
  });

  panelsArray.forEach(function (p) {
    addPanelToDom(p, buttonsVisible);
  });

  panelDragAndDrop.apply();
}

function sendAddPanel(panel) {
  server.sendMessage(Panel.MESSAGE_ADD_PANEL, panel);
}

function sendDeletePanel(id) {
  server.sendMessage(Panel.MESSAGE_DELETE_PANEL, id);
}

function sendUpdatePanel(panel) {
  server.sendMessage(Panel.MESSAGE_UPDATE_PANEL, panel);
}

//function sendMovePanelUp(id) {
//  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_UP, id);
//}
//
//function sendMovePanelDown(id) {
//  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_DOWN, id);
//}
//
//function sendMovePanelLeft(id) {
//  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_LEFT, id);
//}
//
//function sendMovePanelRight(id) {
//  server.sendMessage(Panel.MESSAGE_MOVE_PANEL_RIGHT, id);
//}

function addPanelToDom(panel, buttonsVisible) {
  var displayButtonClass = buttonsVisible ? "displayButton" : "";
  var displayStyle = buttonsVisible ? "block" : "none";

  //$("#columnContainer" + panel.column).append(
  $("#column" + panel.column).append(
    '
' +
    '
' +
    '
' +
    '        <button id="panelBtnAddWidget' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
//    '        <button id="panelBtnRemoveWidget' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
//    '          ' +
//    '        </button>' +
    '        <button id="panelBtnDelete' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
//    '        <button id="panelBtnMoveDown' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
//    '          ' +
//    '        </button>' +
//    '        <button id="panelBtnMoveUp' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
//    '          ' +
//    '        </button>' +
//    '        <button id="panelBtnMoveLeft' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
//    '          ' +
//    '        </button>' +
//    '        <button id="panelBtnMoveRight' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
//    '          ' +
//    '        </button>' +
    '        <button id="panelBtnModify' + panel.id + '" type="button" class="config-buttons btn btn-default btn-sml ' + displayButtonClass + '" style="display: ' + displayStyle + ';">' +
    '          ' +
    '        </button>' +
    '
' +
    '     ' + panel.name + '' +
    '
' +
    '
' +
    '
' +
    '
'
  );

  $('#panel' + panel.id).hide().fadeIn('slow');

  $('#panelBtnAddWidget' + panel.id).on('click', function() {
    viewWidgetWizard('add', {}, panel.id);
  });

  $('#panelBtnDelete' + panel.id).on('click', function() {
    sendDeletePanel(panel.id);
  });

//  $('#panelBtnMoveDown' + panel.id).on('click', function() {
//    sendMovePanelDown(panel.id);
//  });
//
//  $('#panelBtnMoveUp' + panel.id).on('click', function() {
//    sendMovePanelUp(panel.id);
//  });
//
//  $('#panelBtnMoveLeft' + panel.id).on('click', function() {
//    sendMovePanelLeft(panel.id);
//  });
//
//  $('#panelBtnMoveRight' + panel.id).on('click', function() {
//    sendMovePanelRight(panel.id);
//  });
//

  $('#panelBtnModify' + panel.id).on('click', function() {
    displayPanelDialog('update', panel);
  });
}

function deletePanel(id) {
  $('#panel' + id)
    .animate({height: 0, padding: 0, margin: 0}, {easing: "linear", duration: "slow", queue: false})
    .fadeOut('slow', function() {
    this.remove();
  });
}

function movePanelDown(id) {
  var panelList = getPanelList(id);

  if(panelList['panel' + id].position < (Object.keys(panelList).length - 1)) {
    // move down
    swapPanelVertically(panelList['panel' + id].id, panelList['panel' + id].nextId);
  }
}

function movePanelUp(id) {
  var panelList = getPanelList(id);

  if(panelList['panel' + id].position > 0) {
    // move up
    swapPanelVertically(panelList['panel' + id].id, panelList['panel' + id].prevId);
  }
}

function changePanelColumn(panelData) {
  var panel = $('#panel' + panelData.id);

  $('#panel' + panelData.id)
    .animate({height: 0, padding: 0, margin: 0}, {easing: "linear", duration: "fast", queue: false})
    .fadeOut('fast', function() {
      panel
        .appendTo("#columnContainer" + panelData.column)
        .hide()
        .css('height', '')
        .css('padding', '')
        .css('margin', '')
        .fadeIn('fast');

  });
}

function getPanelList(id) {
  var prevPanel = null;
  var nextPanel = null;
  var counter = 0;
  var panelList = {};

  $('#panel' + id).parent().children().each(function() {
    panelList[$(this).attr('id')] = {
      id: $(this).attr('id'),
      position: counter++,
      value: this,
      prevId: null,
      nextId: null
    };

    if(prevPanel !== null) {
      panelList[$(this).attr('id')].prevId = prevPanel.id;
      prevPanel.nextId = $(this).attr('id');
    }

    prevPanel = panelList[$(this).attr('id')];
  });

  return panelList;
}

function swapPanelVertically(a, b){
    a = $('#' + a)[0];
    b = $('#' + b)[0];

    var t = a.parentNode.insertBefore(document.createTextNode(''), a);

    b.parentNode.insertBefore(a, b);
    t.parentNode.insertBefore(b, t);
    t.parentNode.removeChild(t);
}

<|endoftext|>


<commit_before>import expect from 'expect';
import * as ReactIntl from '../../src/react-intl-with-locales';

describe('react-intl-with-locales', () => {
    describe('exports', () => {
        it('exports `addLocaleData`', () => {
            expect(ReactIntl.addLocaleData).toBeA('function');
        });

        it('exports `defineMessages`', () => {
            expect(ReactIntl.defineMessages).toBeA('function');
        });

        it('exports `injectIntl`', () => {
            expect(ReactIntl.injectIntl).toBeA('function');
        });

        describe('React Components', () => {
            it('exports `IntlProvider`', () => {
                expect(ReactIntl.IntlProvider).toBeA('function');
            });

            it('exports `FormattedDate`', () => {
                expect(ReactIntl.FormattedDate).toBeA('function');
            });

            it('exports `FormattedTime`', () => {
                expect(ReactIntl.FormattedTime).toBeA('function');
            });

            it('exports `FormattedRelative`', () => {
                expect(ReactIntl.FormattedRelative).toBeA('function');
            });

            it('exports `FormattedNumber`', () => {
                expect(ReactIntl.FormattedNumber).toBeA('function');
            });

            it('exports `FormattedPlural`', () => {
                expect(ReactIntl.FormattedPlural).toBeA('function');
            });

            it('exports `FormattedMessage`', () => {
                expect(ReactIntl.FormattedMessage).toBeA('function');
            });

            it('exports `FormattedHTMLMessage`', () => {
                expect(ReactIntl.FormattedHTMLMessage).toBeA('function');
            });
        });

        describe('PropTypes Definitions', () => {
            it('exports `intlShape`', () => {
                expect(ReactIntl.intlShape).toBeAn('function');
            });
        });
    });
});
<commit_msg>Update react-intl-with-locales unit tests<commit_after>import expect from 'expect';
import * as ReactIntl from '../../src/react-intl';
import * as ReactIntlWL from '../../src/react-intl-with-locales';

describe('react-intl-with-locales', () => {
    describe('exports', () => {
        it('has the same exports as "react-intl"', () => {
            Object.keys(ReactIntl).forEach((namedExport) => {
                expect(ReactIntlWL[namedExport]).toBe(ReactIntl[namedExport]);
            });
        });
    });
});
<|endoftext|>


<commit_before>//              bricks.js

var updateprops=function(src,dst){
                var srckeys=Object.keys(src)
                var idx=srckeys.length

                while (idx--){
                        var key=srckeys[idx]
                        if (dst[key]){
                                dst[key]=src[key]
                        }

                }
                return dst
}

function show(){
        try {

        console.log('{\n"properties":\n'+JSON.stringify(this.properties)+",")
        }
        catch(err){
                console.log('error showing properties')

        }
        try {

        console.log('"entities":\n'+JSON.stringify(this.entities)+"\n}\n\n")
        }
        catch(err){
        console.log('no entities')
        }
        return
}

function setprop(prop,val){
                if (this.properties[prop]){
                        this.properties[prop]=val
                        console.log(this.properties[prop])
                }
}
module.exports={

// Used to update properties of a brick from the json passed in
updateprops: function(src,dst){
                var srckeys=Object.keys(src)
                var idx=srckeys.length

                while (idx--){
                        var key=srckeys[idx]
                        dst[key]=src[key]
                }
                return dst
},

        datacenter: function(props){

                this.set=setprop
                this.show=show
                this.properties={
                                name : "a Fine Data Center",
                                location : "us/las",
                                description:"a good one"
                                }

                this.entities= {
                                servers: { items: []},
                                lans: {items: []},
                                loadbalancers: {items: []},
                                volumes: {items: [] }
                                }

        if (props){this.properties=updateprops(props,this.properties) }

                this.addServer=function(aserver){
                                this.entities.servers.items.push(aserver)
                }
                this.addLan=function(alan){
                                this.entities.lans.items.push(alan)
                }
                this.addLoadbalancer=function(aloadbalancer){
                                this.entities.loadbalancers.items.push(aloadbalancer)
                }
                this.addVolume=function(avolume){
                                this.entities.volumes.items.push(avolume)
                }

                return this
        },

        server: function(props){
                this.set=setprop
                this.show=show
                this.properties={
                                name : "f",
                                ram : "3192",
                                cores : "1"
                                }

                this.entities={
                                cdroms: { items: []},
                                nics: {items: []},
                                volumes: {items: [] }
                                }

                if (props){this.properties=updateprops(props,this.properties) }

                this.addNic=function(anic){
                        this.entities.nics.items.push(anic)
                }

                return this
        },

        nic: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                                name: "name",
                                ips: [],
                                lan:1
                                }

                this.entities={
                                firewallrules: {items: []}
                                }

                this.addFwrule=function(afwrule){
                        this.entities.firewallrules.items.push(afwrule)
                }

                return this
        },

        firewallrule:   function (props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                        name: "port",
                        protocol: "TCP",
                        sourceMac: "",
                        sourceIp: '',
                        targetIp: '',
                        portRangeStart: 0,
                        portRangeEnd: "",
                        icmpType: "",
                        icmpCode: ""
                }
        },

        image: function (props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                        name: "Ubuntu 14.04",
                        description: "Ubuntu image description",
                        location: "de/fkb",
                        size: 28,
                        public: false,
                        imageType: "CDROM",
                        licenceType: "UNKNOWN"
                         }
                return this
        },

        ipblock: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties= {
                        size: 5,
                        location: "de/fra"
                }
                return this
        },

        loadbalancer: function (props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                                name: "",
                                ip: "",
                                dhcp: ""
                                }

                this.entities={
                                balancednics: { items: [] }
                                }

                this.addBalancedNic=function(abalnic){
                        this.entities.balancednics.items.push(abalnic)
                }

                return this
        },

        lan: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                                name: "",
                                public: ""
                                }

                this.entities={
                        nics: { items: [] }
                }

                this.addNic=function(anic){
                        this.entities.nics.items.push(anic)
                }

                return this
        },

        snapshot: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties= {
                        name: "The Snapshot",
                        description: "description of a snapshot",
                        location: "de/fkb",
                        size: 28,
                        licenceType: "UNKNOWN"
                        }

                return this
        },

        volume: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties= {
                        name: "v is for volume",
                        size: 80,
                        bus: "VIRTIO",
                        type: "HDD",
                        licenceType: "UNKNOWN"
                }

                return this
        }

}
<commit_msg>Update bricks.js<commit_after>//              bricks.js

function show(){
        try {

        console.log('{\n"properties":\n'+JSON.stringify(this.properties)+",")
        }
        catch(err){
                console.log('error showing properties')

        }
        try {

        console.log('"entities":\n'+JSON.stringify(this.entities)+"\n}\n\n")
        }
        catch(err){
        console.log('no entities')
        }
        return
}

function setprop(prop,val){
                if (this.properties[prop]){
                        this.properties[prop]=val
                        console.log(this.properties[prop])
                }
}
module.exports={

// Used to update properties of a brick from the json passed in
updateprops: function(src,dst){
                var srckeys=Object.keys(src)
                var idx=srckeys.length

                while (idx--){
                        var key=srckeys[idx]
                        dst[key]=src[key]
                }
                return dst
},

        datacenter: function(props){

                this.set=setprop
                this.show=show
                this.properties={
                                name : "a Fine Data Center",
                                location : "us/las",
                                description:"a good one"
                                }

                this.entities= {
                                servers: { items: []},
                                lans: {items: []},
                                loadbalancers: {items: []},
                                volumes: {items: [] }
                                }

        if (props){this.properties=updateprops(props,this.properties) }

                this.addServer=function(aserver){
                                this.entities.servers.items.push(aserver)
                }
                this.addLan=function(alan){
                                this.entities.lans.items.push(alan)
                }
                this.addLoadbalancer=function(aloadbalancer){
                                this.entities.loadbalancers.items.push(aloadbalancer)
                }
                this.addVolume=function(avolume){
                                this.entities.volumes.items.push(avolume)
                }

                return this
        },

        server: function(props){
                this.set=setprop
                this.show=show
                this.properties={
                                name : "f",
                                ram : "3192",
                                cores : "1"
                                }

                this.entities={
                                cdroms: { items: []},
                                nics: {items: []},
                                volumes: {items: [] }
                                }

                if (props){this.properties=updateprops(props,this.properties) }

                this.addNic=function(anic){
                        this.entities.nics.items.push(anic)
                }

                return this
        },

        nic: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                                name: "name",
                                ips: [],
                                lan:1
                                }

                this.entities={
                                firewallrules: {items: []}
                                }

                this.addFwrule=function(afwrule){
                        this.entities.firewallrules.items.push(afwrule)
                }

                return this
        },

        firewallrule:   function (props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                        name: "port",
                        protocol: "TCP",
                        sourceMac: "",
                        sourceIp: '',
                        targetIp: '',
                        portRangeStart: 0,
                        portRangeEnd: "",
                        icmpType: "",
                        icmpCode: ""
                }
        },

        image: function (props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                        name: "Ubuntu 14.04",
                        description: "Ubuntu image description",
                        location: "de/fkb",
                        size: 28,
                        public: false,
                        imageType: "CDROM",
                        licenceType: "UNKNOWN"
                         }
                return this
        },

        ipblock: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties= {
                        size: 5,
                        location: "de/fra"
                }
                return this
        },

        loadbalancer: function (props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                                name: "",
                                ip: "",
                                dhcp: ""
                                }

                this.entities={
                                balancednics: { items: [] }
                                }

                this.addBalancedNic=function(abalnic){
                        this.entities.balancednics.items.push(abalnic)
                }

                return this
        },

        lan: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties={
                                name: "",
                                public: ""
                                }

                this.entities={
                        nics: { items: [] }
                }

                this.addNic=function(anic){
                        this.entities.nics.items.push(anic)
                }

                return this
        },

        snapshot: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties= {
                        name: "The Snapshot",
                        description: "description of a snapshot",
                        location: "de/fkb",
                        size: 28,
                        licenceType: "UNKNOWN"
                        }

                return this
        },

        volume: function(props){
                if (props){this.properties=updateprops(props,this.properties) }
                this.set=setprop
                this.show=show
                this.properties= {
                        name: "v is for volume",
                        size: 80,
                        bus: "VIRTIO",
                        type: "HDD",
                        licenceType: "UNKNOWN"
                }

                return this
        }

}
<|endoftext|>


<commit_before>var BossStateMachine = function () {
    this.end();
};

BossStateMachine.prototype.startBoss = function (boss) {
    if (this.currentBoss === boss) {
        return;
    }
    cactbot.debug('Boss fight: ' + boss.bossName);
    var currentTime = new Date();
    this.currentBoss = boss;
    this.currentBossStartTime = currentTime;
    this.startPhase(0, currentTime);
};

BossStateMachine.prototype.end = function () {
    if (!this.currentBoss) {
        return;
    }
    cactbot.debug('End boss fight');
    this.currentBoss = null;
    this.currentPhase = null;
    this.currentBossStartTime = null;
    this.currentPhaseStartTime = null;
    this.currentRotation = [];
};

BossStateMachine.prototype.startPhase = function (phaseNumber, currentTime) {
    if (this.currentPhase === phaseNumber)
        return;
    this.currentPhase = phaseNumber;
    this.currentPhaseStartTime = currentTime;

    // Some loops have a "one time" part of the loop that happens in negative
    // time, so move time=0 into the future.
    var phase = this.currentBoss.phases[this.currentPhase];
    if (typeof phase.loopOffset === 'number') {
        this.currentPhaseStartTime = addTime(currentTime, -phase.loopOffset);
    }
};

BossStateMachine.prototype.processLog = function (logLine) {
    if (!this.currentBoss) {
        return;
    }
    var phase = this.currentBoss.phases[this.currentPhase];
    if (!phase.endLog) {
        return;
    }
    if (logLine.indexOf(phase.endLog) != -1) {
        var currentTime = new Date();
        this.startPhase(this.currentPhase + 1, currentTime);
    }
    // FIXME: only allow echos to do this vs jerks saying this in chat.
    if (logLine.indexOf("cactbot wipe") != -1) {
        this.end();
    }
};

BossStateMachine.prototype.tick = function (currentTime) {
    if (!this.currentBoss)
        return;

    if (this.currentBoss.enrageSeconds) {
        var enrage = addTime(currentTime, this.currentBoss.enrageSeconds);
        if (enrage < currentTime) {
            // TODO: enrage
            return;
        }
    }

    var phase = this.currentBoss.phases[this.currentPhase];
    if (phase.endSeconds) {
        var endPhase = addTime(this.currentPhaseStartTime, phase.endSeconds);
        if (endPhase < currentTime) {
            this.startPhase(this.currentPhase + 1, currentTime);
        }
    }

    if (phase.justText) {
        this.currentRotation = phase.rotation;
        return;
    }

    // Note: boss percent never changes phase, it's just currently there for status.

    var rotation = [];
    var seconds = (currentTime.getTime() - this.currentPhaseStartTime.getTime()) / 1000;
    var adjustedStartTime = this.currentPhaseStartTime;
    if (phase.loop) {
        // FIXME: assert if no loopSeconds.
        seconds = seconds % phase.loopSeconds;
        adjustedStartTime = addTime(currentTime, -seconds);
    }
    for (var startIdx = 0; startIdx < phase.rotation.length; ++startIdx) {
        var item = phase.rotation[startIdx];
        if (item.time > seconds)
            break;
    }
    // assert startIdx is valid here
    var adjustedItem;
    for (var i = startIdx; i < phase.rotation.length; ++i) {
        if (phase.rotation[i].skipFirst) {
            continue;
        }
        adjustedItem = {
            name: phase.rotation[i].name,
            time: addTime(adjustedStartTime, phase.rotation[i].time),
        };
        rotation.push(adjustedItem);
    }

    if (phase.loop) {
        var nextLoop = addTime(adjustedStartTime, phase.loopSeconds);
        for (var i = 0; i < startIdx; ++i) {
            if (phase.rotation[i].justOnce) {
                continue;
            }
            adjustedItem = {
                name: phase.rotation[i].name,
                time: addTime(nextLoop, phase.rotation[i].time),
            };
            rotation.push(adjustedItem);
        }
    }

    this.currentRotation = rotation;
};

var RaidTimersBinding = function() {
    this.boundData = {};
    this.boundElementNames = {};
    this.boundFuncs = {};
    this.initialValues = {};

    this.register('title', 'bosstitle', this.updateInnerText, '');
    this.register('enrage', 'enrage', this.updateInnerText, '');
    this.register('nextTitle', 'nextphasetitle', this.updateInnerText, '');
    this.register('nextCondition', 'nextphasecondition', this.updateInnerText, '');
    this.register('rotation', 'rotation', this.updateRotation, []);

    this.clear();
};

RaidTimersBinding.prototype.clear = function() {
    for (var id in this.initialValues) {
        this.setterInner(id, this.initialValues[id]);
    }
};

RaidTimersBinding.prototype.register = function(id, elementName, func, initial) {
    var setterName = "set" + id[0].toUpperCase() + id.substring(1);
    this[setterName] = function(value) {
        return this.setterInner(id, value);
    };
    this.boundElementNames[id] = elementName;
    this.boundFuncs[id] = func;
    this.initialValues[id] = initial;
};

RaidTimersBinding.prototype.setterInner = function(id, value) {
    if (this.boundData[id] === value)
        return;
    this.boundData[id] = value;

    var element = document.getElementById(this.boundElementNames[id]);
    if (!element) {
        // TODO: warning
        return;
    }
    this.boundFuncs[id](element, value);
};

RaidTimersBinding.prototype.updateInnerText = function(element, value) {
    element.innerText = value;
};

RaidTimersBinding.prototype.updateRotation = function(rotationDiv, rotation) {
    var currentTime = new Date();

    rotationDiv.innerHTML = "";

    // Limit by height? Or by count?
    for (var i = 0; i < rotation.length; ++i) {
        var rotItem = document.createElement("div");
        rotItem.className = "rotitem";

        var moveItem = document.createElement("div");
        moveItem.className = "move";
        moveItem.innerText = rotation[i].name;
        rotItem.appendChild(moveItem);

        var countdownItem = document.createElement("div");
        countdownItem.className = "countdown";
        if (rotation[i].time) {
            countdownItem.innerText = formatTimeDiff(rotation[i].time, currentTime);
        }
        rotItem.appendChild(countdownItem);

        rotationDiv.appendChild(rotItem);
    }
};

function addTime(date, seconds) {
    return new Date(date.getTime() + seconds * 1000);
}

function formatTimeDiff(futureTime, currentTime) {
    var total = (futureTime.getTime() - currentTime.getTime()) / 1000;
    return formatTime(total);
}

function formatTime(totalSeconds) {
    var str = "";
    var total = Math.max(0, totalSeconds);
    var minutes = Math.floor(total / 60);
    var seconds = Math.floor(total % 60);
    var tenthseconds = Math.floor((10 * (total % 60)) % 10);
    str = "";
    if (minutes > 0)
        str += minutes + "m";
    str += seconds;
    if (!minutes)
        str += "." + tenthseconds;
    str += "s";

    return str;
}

var bindings;

function hpPercentByName(name) {
    var combatant = window.act.getMobByName(name);
    if (!combatant)
        return 0;
    return 100 * combatant.currentHP / combatant.maxHP;
}

function updateFunc(bossStateMachine) {
    var boss = bossStateMachine.currentBoss;
    if (!boss) {
        bindings.clear();
        return;
    }

    var percent = hpPercentByName(boss.bossName);
    percent = Math.floor(percent); // TODO: add one decimal point
    bindings.setTitle(boss.bossName + ": " + percent + "%");

    var currentTime = new Date();

    var enrageSeconds = boss.enrageSeconds;
    if (enrageSeconds) {
        var enrage = addTime(bossStateMachine.currentBossStartTime, enrageSeconds);
        bindings.setEnrage("Enrage: " + formatTimeDiff(enrage, currentTime));
    } else {
        bindings.setEnrage('');
    }

    var currentPhase = boss.phases[bossStateMachine.currentPhase];
    var nextPhase = boss.phases[bossStateMachine.currentPhase + 1];

    // TODO: Add one rotation from next phase as well when it gets
    // close in time or percentage? Or always?
    var nextPhaseTitle = "";
    var nextPhaseTime = "";
    if (nextPhase) {
        nextPhaseTitle = nextPhase.title;
        if (currentPhase.endSeconds) {
            var phaseEndTime = addTime(bossStateMachine.currentPhaseStartTime, currentPhase.endSeconds);
            nextPhaseTime = formatTimeDiff(phaseEndTime, currentTime);
        } else if (currentPhase.endHpPercent) {
            nextPhaseTime = currentPhase.endHpPercent + "%";
        }
    }
    bindings.setNextTitle(nextPhaseTitle);
    bindings.setNextCondition(nextPhaseTime);

    bindings.setRotation(bossStateMachine.currentRotation);
}

var BaseTickable = function () {
    this.boss = new BossStateMachine();
};

BaseTickable.prototype.enterZone = function (zone) {
};

BaseTickable.prototype.leaveZone = function (zone) {
};

BaseTickable.prototype.filtersZone = function (zone) {
    if (!this.zoneFilter)
        return true;
    return this.zoneFilter === zone;
};
BaseTickable.prototype.tick = function (currentTime) {
    this.boss.tick(currentTime);

    // FIXME: This isn't a great place to glue a state machine to bindings.
    updateFunc(this.boss);
};

BaseTickable.prototype.processLog = function (log) {
    if (log.indexOf("will be sealed off") != -1) {
        for (var i = 0; i < this.bosses.length; ++i) {
            if (log.indexOf(this.bosses[i].areaSeal) == -1) {
                continue;
            }
            // FIXME: Use log entry time to start?
            this.boss.startBoss(this.bosses[i]);
            break;
        }
    } else if (log.indexOf("is no longer sealed") != -1) {
        for (var i = 0; i < this.bosses.length; ++i) {
            if (log.indexOf(this.bosses[i].areaSeal) == -1)
                continue;
            this.boss.stop();
            break;
        }
    }

    for (var i = 0; i < this.bosses.length; ++i) {
        if (!this.bosses[i].startLog) {
            continue;
        }
        if (log.indexOf(this.bosses[i].startLog) == -1) {
            continue;
        }
        this.boss.startBoss(this.bosses[i]);
        break;
    }

    if (this.boss) {
        this.boss.processLog(log);
    }
};

window.addEventListener("load", function () {
    window.loadCSS("rotation/rotation.css");

    // FIXME: This can't get loaded from a file via Javascript, because of
    // cross-origin issues.  This isn't an issue at runtime (cef can cheat
    // the sandbox with some flags), but it will make developing a pain if
    // it's required to run a proxy or pass sandbox-clobbering flags to
    // the browser.  Punt on adding more developer hurdles for now.  <_<
    var element = document.createElement("div");
    element.innerHTML =
        '
' +
        '
' +
        '
Angry Bees: 0%
' +
        '
Enrage: 12m10s
' +
        '
' +
        '
' +
        '

next thing

1m24s

' +
        '

one thing

1m24s

' +
        '

that thing

2m24s

' +
        '

whoa whoa whoa

3m24s

' +
        '
' +
        '
' +
        '
Phase 2 (dem adds)
' +
        '
HP: 61%, 1m25s
' +
        '
' +
        '
';

    var body = document.getElementsByTagName("body")[0];
    body.appendChild(element);

    var defaultGeometry = {
        width: "400px",
        height: "400px",
    };

    windowManager.add("rotation", element, "rotation", defaultGeometry);

    // FIXME: This is such a clumsy binding.
    window.bindings = new RaidTimersBinding();
});<commit_msg>Have zones print their bosses<commit_after>var BossStateMachine = function () {
    this.end();
};

BossStateMachine.prototype.startBoss = function (boss) {
    if (this.currentBoss === boss) {
        return;
    }
    cactbot.debug('Boss fight: ' + boss.bossName);
    var currentTime = new Date();
    this.currentBoss = boss;
    this.currentBossStartTime = currentTime;
    this.startPhase(0, currentTime);
};

BossStateMachine.prototype.end = function () {
    if (!this.currentBoss) {
        return;
    }
    cactbot.debug('End boss fight');
    this.currentBoss = null;
    this.currentPhase = null;
    this.currentBossStartTime = null;
    this.currentPhaseStartTime = null;
    this.currentRotation = [];
};

BossStateMachine.prototype.startPhase = function (phaseNumber, currentTime) {
    if (this.currentPhase === phaseNumber)
        return;
    this.currentPhase = phaseNumber;
    this.currentPhaseStartTime = currentTime;

    // Some loops have a "one time" part of the loop that happens in negative
    // time, so move time=0 into the future.
    var phase = this.currentBoss.phases[this.currentPhase];
    if (typeof phase.loopOffset === 'number') {
        this.currentPhaseStartTime = addTime(currentTime, -phase.loopOffset);
    }
};

BossStateMachine.prototype.processLog = function (logLine) {
    if (!this.currentBoss) {
        return;
    }
    var phase = this.currentBoss.phases[this.currentPhase];
    if (!phase.endLog) {
        return;
    }
    if (logLine.indexOf(phase.endLog) != -1) {
        var currentTime = new Date();
        this.startPhase(this.currentPhase + 1, currentTime);
    }
    // FIXME: only allow echos to do this vs jerks saying this in chat.
    if (logLine.indexOf("cactbot wipe") != -1) {
        this.end();
    }
};

BossStateMachine.prototype.tick = function (currentTime) {
    if (!this.currentBoss)
        return;

    if (this.currentBoss.enrageSeconds) {
        var enrage = addTime(currentTime, this.currentBoss.enrageSeconds);
        if (enrage < currentTime) {
            // TODO: enrage
            return;
        }
    }

    var phase = this.currentBoss.phases[this.currentPhase];
    if (phase.endSeconds) {
        var endPhase = addTime(this.currentPhaseStartTime, phase.endSeconds);
        if (endPhase < currentTime) {
            this.startPhase(this.currentPhase + 1, currentTime);
        }
    }

    if (phase.justText) {
        this.currentRotation = phase.rotation;
        return;
    }

    // Note: boss percent never changes phase, it's just currently there for status.

    var rotation = [];
    var seconds = (currentTime.getTime() - this.currentPhaseStartTime.getTime()) / 1000;
    var adjustedStartTime = this.currentPhaseStartTime;
    if (phase.loop) {
        // FIXME: assert if no loopSeconds.
        seconds = seconds % phase.loopSeconds;
        adjustedStartTime = addTime(currentTime, -seconds);
    }
    for (var startIdx = 0; startIdx < phase.rotation.length; ++startIdx) {
        var item = phase.rotation[startIdx];
        if (item.time > seconds)
            break;
    }
    // assert startIdx is valid here
    var adjustedItem;
    for (var i = startIdx; i < phase.rotation.length; ++i) {
        if (phase.rotation[i].skipFirst) {
            continue;
        }
        adjustedItem = {
            name: phase.rotation[i].name,
            time: addTime(adjustedStartTime, phase.rotation[i].time),
        };
        rotation.push(adjustedItem);
    }

    if (phase.loop) {
        var nextLoop = addTime(adjustedStartTime, phase.loopSeconds);
        for (var i = 0; i < startIdx; ++i) {
            if (phase.rotation[i].justOnce) {
                continue;
            }
            adjustedItem = {
                name: phase.rotation[i].name,
                time: addTime(nextLoop, phase.rotation[i].time),
            };
            rotation.push(adjustedItem);
        }
    }

    this.currentRotation = rotation;
};

var RaidTimersBinding = function() {
    this.boundData = {};
    this.boundElementNames = {};
    this.boundFuncs = {};
    this.initialValues = {};

    this.register('title', 'bosstitle', this.updateInnerText, '');
    this.register('enrage', 'enrage', this.updateInnerText, '');
    this.register('nextTitle', 'nextphasetitle', this.updateInnerText, '');
    this.register('nextCondition', 'nextphasecondition', this.updateInnerText, '');
    this.register('rotation', 'rotation', this.updateRotation, []);

    this.clear();
};

RaidTimersBinding.prototype.clear = function() {
    for (var id in this.initialValues) {
        this.setterInner(id, this.initialValues[id]);
    }
};

RaidTimersBinding.prototype.register = function(id, elementName, func, initial) {
    var setterName = "set" + id[0].toUpperCase() + id.substring(1);
    this[setterName] = function(value) {
        return this.setterInner(id, value);
    };
    this.boundElementNames[id] = elementName;
    this.boundFuncs[id] = func;
    this.initialValues[id] = initial;
};

RaidTimersBinding.prototype.setterInner = function(id, value) {
    if (this.boundData[id] === value)
        return;
    this.boundData[id] = value;

    var element = document.getElementById(this.boundElementNames[id]);
    if (!element) {
        // TODO: warning
        return;
    }
    this.boundFuncs[id](element, value);
};

RaidTimersBinding.prototype.updateInnerText = function(element, value) {
    element.innerText = value;
};

RaidTimersBinding.prototype.updateRotation = function(rotationDiv, rotation) {
    var currentTime = new Date();

    rotationDiv.innerHTML = "";

    // Limit by height? Or by count?
    for (var i = 0; i < rotation.length; ++i) {
        var rotItem = document.createElement("div");
        rotItem.className = "rotitem";

        var moveItem = document.createElement("div");
        moveItem.className = "move";
        moveItem.innerText = rotation[i].name;
        rotItem.appendChild(moveItem);

        var countdownItem = document.createElement("div");
        countdownItem.className = "countdown";
        if (rotation[i].time) {
            countdownItem.innerText = formatTimeDiff(rotation[i].time, currentTime);
        }
        rotItem.appendChild(countdownItem);

        rotationDiv.appendChild(rotItem);
    }
};

function addTime(date, seconds) {
    return new Date(date.getTime() + seconds * 1000);
}

function formatTimeDiff(futureTime, currentTime) {
    var total = (futureTime.getTime() - currentTime.getTime()) / 1000;
    return formatTime(total);
}

function formatTime(totalSeconds) {
    var str = "";
    var total = Math.max(0, totalSeconds);
    var minutes = Math.floor(total / 60);
    var seconds = Math.floor(total % 60);
    var tenthseconds = Math.floor((10 * (total % 60)) % 10);
    str = "";
    if (minutes > 0)
        str += minutes + "m";
    str += seconds;
    if (!minutes)
        str += "." + tenthseconds;
    str += "s";

    return str;
}

var bindings;

function hpPercentByName(name) {
    var combatant = window.act.getMobByName(name);
    if (!combatant)
        return 0;
    return 100 * combatant.currentHP / combatant.maxHP;
}

function updateFunc(bossStateMachine) {
    var boss = bossStateMachine.currentBoss;
    if (!boss) {
        bindings.clear();
        return;
    }

    var percent = hpPercentByName(boss.bossName);
    percent = Math.floor(percent); // TODO: add one decimal point
    bindings.setTitle(boss.bossName + ": " + percent + "%");

    var currentTime = new Date();

    var enrageSeconds = boss.enrageSeconds;
    if (enrageSeconds) {
        var enrage = addTime(bossStateMachine.currentBossStartTime, enrageSeconds);
        bindings.setEnrage("Enrage: " + formatTimeDiff(enrage, currentTime));
    } else {
        bindings.setEnrage('');
    }

    var currentPhase = boss.phases[bossStateMachine.currentPhase];
    var nextPhase = boss.phases[bossStateMachine.currentPhase + 1];

    // TODO: Add one rotation from next phase as well when it gets
    // close in time or percentage? Or always?
    var nextPhaseTitle = "";
    var nextPhaseTime = "";
    if (nextPhase) {
        nextPhaseTitle = nextPhase.title;
        if (currentPhase.endSeconds) {
            var phaseEndTime = addTime(bossStateMachine.currentPhaseStartTime, currentPhase.endSeconds);
            nextPhaseTime = formatTimeDiff(phaseEndTime, currentTime);
        } else if (currentPhase.endHpPercent) {
            nextPhaseTime = currentPhase.endHpPercent + "%";
        }
    }
    bindings.setNextTitle(nextPhaseTitle);
    bindings.setNextCondition(nextPhaseTime);

    bindings.setRotation(bossStateMachine.currentRotation);
}

var BaseTickable = function () {
    this.boss = new BossStateMachine();
};

BaseTickable.prototype.enterZone = function (zone) {
    for (var i = 0; i < this.bosses.length; ++i) {
        cactbot.debug('Added boss: ' + this.bosses[i].bossName);
    }
};

BaseTickable.prototype.leaveZone = function (zone) {
};

BaseTickable.prototype.filtersZone = function (zone) {
    if (!this.zoneFilter)
        return true;
    return this.zoneFilter === zone;
};
BaseTickable.prototype.tick = function (currentTime) {
    this.boss.tick(currentTime);

    // FIXME: This isn't a great place to glue a state machine to bindings.
    updateFunc(this.boss);
};

BaseTickable.prototype.processLog = function (log) {
    if (log.indexOf("will be sealed off") != -1) {
        for (var i = 0; i < this.bosses.length; ++i) {
            if (log.indexOf(this.bosses[i].areaSeal) == -1) {
                continue;
            }
            // FIXME: Use log entry time to start?
            this.boss.startBoss(this.bosses[i]);
            break;
        }
    } else if (log.indexOf("is no longer sealed") != -1) {
        for (var i = 0; i < this.bosses.length; ++i) {
            if (log.indexOf(this.bosses[i].areaSeal) == -1)
                continue;
            this.boss.stop();
            break;
        }
    }

    for (var i = 0; i < this.bosses.length; ++i) {
        if (!this.bosses[i].startLog) {
            continue;
        }
        if (log.indexOf(this.bosses[i].startLog) == -1) {
            continue;
        }
        this.boss.startBoss(this.bosses[i]);
        break;
    }

    if (this.boss) {
        this.boss.processLog(log);
    }
};

window.addEventListener("load", function () {
    window.loadCSS("rotation/rotation.css");

    // FIXME: This can't get loaded from a file via Javascript, because of
    // cross-origin issues.  This isn't an issue at runtime (cef can cheat
    // the sandbox with some flags), but it will make developing a pain if
    // it's required to run a proxy or pass sandbox-clobbering flags to
    // the browser.  Punt on adding more developer hurdles for now.  <_<
    var element = document.createElement("div");
    element.innerHTML =
        '
' +
        '
' +
        '
Angry Bees: 0%
' +
        '
Enrage: 12m10s
' +
        '
' +
        '
' +
        '

next thing

1m24s

' +
        '

one thing

1m24s

' +
        '

that thing

2m24s

' +
        '

whoa whoa whoa

3m24s

' +
        '
' +
        '
' +
        '
Phase 2 (dem adds)
' +
        '
HP: 61%, 1m25s
' +
        '
' +
        '
';

    var body = document.getElementsByTagName("body")[0];
    body.appendChild(element);

    var defaultGeometry = {
        width: "400px",
        height: "400px",
    };

    windowManager.add("rotation", element, "rotation", defaultGeometry);

    // FIXME: This is such a clumsy binding.
    window.bindings = new RaidTimersBinding();
});<|endoftext|>


<commit_before>var utils = module.exports = exports = {
  SHA1: require('./sha1')
};

// Extend existing objects without creating references
//
// Return: `Object`
utils.extend = function (original, context) {
  var output = JSON.parse(JSON.stringify(original || {})), key;
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        output[key] = utils.extend(output[key] || {}, context[key]);
      else
        output[key] = context[key];
  return output;
};

// Extend objects and convert them to a serialized query string
//
// Return: `Object`
utils.serialExtend = function (original, context, prefix) {
  var output = JSON.parse(JSON.stringify(original || {})), i, key, value;
  for (i in context) {
    if (!context.hasOwnProperty(i)) continue;
    else key = prefix ? prefix + "[" + i + "]" : i, value = context[i];
    if (Object.prototype.toString.call(value) === '[object Object]')
      output = utils.serialExtend(output, value, key);
    else
      output[key] = value;
  }
  return output;
};

// Checks whether host closes their connection early
//
// Return: `Boolean`
utils.isAnEarlyCloseHost = function (hostname) {
  return hostname && hostname.match(".*google(apis)?.com$");
};

// Determines whether response contains Binary content
//
// Return: `Boolean`
utils.isBinaryContent = function (response) {
  return (!response.headers || !response.headers["content-type"]) ? false : (response.headers["content-type"].match(/^(image|audio|video)\//));
};

// Removes leading and trailing whitespace
//
// Return: `String`
utils.trim = function (string) {
  return string.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};

// Encodes and replaces values that encodeURIComponent doesn't.
// The only ones you can ignore with OAuth are: - _ . ~
// see - http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent
//
// Return: `String`
utils.encodeData = function (data) {
  if (data === "" || !data) return "";
  return encodeURIComponent(data).
    replace(/\!/g, "%21").
    replace(/\'/g, "%27").
    replace(/\(/g, "%28").
    replace(/\)/g, "%29").
    replace(/\*/g, "%2A");
};

// Decode URI information with regards to encoding process
//
// Return: `String`
utils.decodeData = function (data) {
  if (data !== null) data = data.replace(/\+/g, ' ');
  return decodeURIComponent(data);
};

// Scans header string for key-value information and bearer details
//
// Return: `Object` unless invalid headers then `Boolean` (false).
utils.parseHeader = function (header) {
  if (header.indexOf(',') === -1) return false;
  var params = {}, match;
  header = utils.trim(header);

  header.split(",").forEach(function (v, i) {
    match = v.match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;]+)?"?)?/);

    if (match[2] === "=")
      params[match[1]] = utils.decodeData(match[3] || "");
    else {
      params['bearer'] = utils.decodeData(match[1]);

      if (match.input.indexOf(" ")) {
        match = match.input.split(" ")[1].match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;\.]+)?"?)?/);
        if (match[2] === "=") params[match[1]] = utils.decodeData(match[3] || "");
      }
    }
  });

  return params;
};<commit_msg>check for text instead of binary<commit_after>var utils = module.exports = exports = {
  SHA1: require('./sha1')
};

// Extend existing objects without creating references
//
// Return: `Object`
utils.extend = function (original, context) {
  var output = JSON.parse(JSON.stringify(original || {})), key;
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        output[key] = utils.extend(output[key] || {}, context[key]);
      else
        output[key] = context[key];
  return output;
};

// Extend objects and convert them to a serialized query string
//
// Return: `Object`
utils.serialExtend = function (original, context, prefix) {
  var output = JSON.parse(JSON.stringify(original || {})), i, key, value;
  for (i in context) {
    if (!context.hasOwnProperty(i)) continue;
    else key = prefix ? prefix + "[" + i + "]" : i, value = context[i];
    if (Object.prototype.toString.call(value) === '[object Object]')
      output = utils.serialExtend(output, value, key);
    else
      output[key] = value;
  }
  return output;
};

// Checks whether host closes their connection early
//
// Return: `Boolean`
utils.isAnEarlyCloseHost = function (hostname) {
  return hostname && hostname.match(".*google(apis)?.com$");
};

// Determines whether response contains Binary content
//
// Return: `Boolean`
utils.isBinaryContent = function (response) {
  return (!response.headers || !response.headers["content-type"])
    ? false
    : (response.headers["content-type"].match(/^(text|html|json|doc|xml|html|rss|form|javascript|ecmascript)/)
      ? false
      : true;
};

// Removes leading and trailing whitespace
//
// Return: `String`
utils.trim = function (string) {
  return string.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};

// Encodes and replaces values that encodeURIComponent doesn't.
// The only ones you can ignore with OAuth are: - _ . ~
// see - http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent
//
// Return: `String`
utils.encodeData = function (data) {
  if (data === "" || !data) return "";
  return encodeURIComponent(data).
    replace(/\!/g, "%21").
    replace(/\'/g, "%27").
    replace(/\(/g, "%28").
    replace(/\)/g, "%29").
    replace(/\*/g, "%2A");
};

// Decode URI information with regards to encoding process
//
// Return: `String`
utils.decodeData = function (data) {
  if (data !== null) data = data.replace(/\+/g, ' ');
  return decodeURIComponent(data);
};

// Scans header string for key-value information and bearer details
//
// Return: `Object` unless invalid headers then `Boolean` (false).
utils.parseHeader = function (header) {
  if (header.indexOf(',') === -1) return false;
  var params = {}, match;
  header = utils.trim(header);

  header.split(",").forEach(function (v, i) {
    match = v.match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;]+)?"?)?/);

    if (match[2] === "=")
      params[match[1]] = utils.decodeData(match[3] || "");
    else {
      params['bearer'] = utils.decodeData(match[1]);

      if (match.input.indexOf(" ")) {
        match = match.input.split(" ")[1].match(/(\w+)(?:([:=]) ?"?([\w\+\%\=\;\.]+)?"?)?/);
        if (match[2] === "=") params[match[1]] = utils.decodeData(match[3] || "");
      }
    }
  });

  return params;
};<|endoftext|>