// Copyright (C) 2016 The Android Open Source Project
//
// 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.
(function() {
  'use strict';

  const EventType = {
    HISTORY: 'history',
    LABEL_CHANGE: 'labelchange',
    SHOW_CHANGE: 'showchange',
    SUBMIT_CHANGE: 'submitchange',
    COMMIT_MSG_EDIT: 'commitmsgedit',
    COMMENT: 'comment',
    REVERT: 'revert',
    POST_REVERT: 'postrevert',
    ANNOTATE_DIFF: 'annotatediff',
  };

  const Element = {
    CHANGE_ACTIONS: 'changeactions',
    REPLY_DIALOG: 'replydialog',
  };

  Polymer({
    is: 'gr-js-api-interface',

    properties: {
      _elements: {
        type: Object,
        value: {}, // Shared across all instances.
      },
      _eventCallbacks: {
        type: Object,
        value: {}, // Shared across all instances.
      },
    },

    behaviors: [Gerrit.PatchSetBehavior],

    Element,
    EventType,

    handleEvent(type, detail) {
      Gerrit.awaitPluginsLoaded().then(() => {
        switch (type) {
          case EventType.HISTORY:
            this._handleHistory(detail);
            break;
          case EventType.SHOW_CHANGE:
            this._handleShowChange(detail);
            break;
          case EventType.COMMENT:
            this._handleComment(detail);
            break;
          case EventType.LABEL_CHANGE:
            this._handleLabelChange(detail);
            break;
          default:
            console.warn('handleEvent called with unsupported event type:',
                type);
            break;
        }
      });
    },

    addElement(key, el) {
      this._elements[key] = el;
    },

    getElement(key) {
      return this._elements[key];
    },

    addEventCallback(eventName, callback) {
      if (!this._eventCallbacks[eventName]) {
        this._eventCallbacks[eventName] = [];
      }
      this._eventCallbacks[eventName].push(callback);
    },

    canSubmitChange(change, revision) {
      const submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE);
      const cancelSubmit = submitCallbacks.some(callback => {
        try {
          return callback(change, revision) === false;
        } catch (err) {
          console.error(err);
        }
        return false;
      });

      return !cancelSubmit;
    },

    _removeEventCallbacks() {
      for (const k in EventType) {
        if (!EventType.hasOwnProperty(k)) { continue; }
        this._eventCallbacks[EventType[k]] = [];
      }
    },

    _handleHistory(detail) {
      for (const cb of this._getEventCallbacks(EventType.HISTORY)) {
        try {
          cb(detail.path);
        } catch (err) {
          console.error(err);
        }
      }
    },

    _handleShowChange(detail) {
      for (const cb of this._getEventCallbacks(EventType.SHOW_CHANGE)) {
        const change = detail.change;
        const patchNum = detail.patchNum;
        let revision;
        for (const rev of Object.values(change.revisions || {})) {
          if (this.patchNumEquals(rev._number, patchNum)) {
            revision = rev;
            break;
          }
        }
        try {
          cb(change, revision);
        } catch (err) {
          console.error(err);
        }
      }
    },

    handleCommitMessage(change, msg) {
      for (const cb of this._getEventCallbacks(EventType.COMMIT_MSG_EDIT)) {
        try {
          cb(change, msg);
        } catch (err) {
          console.error(err);
        }
      }
    },

    _handleComment(detail) {
      for (const cb of this._getEventCallbacks(EventType.COMMENT)) {
        try {
          cb(detail.node);
        } catch (err) {
          console.error(err);
        }
      }
    },

    _handleLabelChange(detail) {
      for (const cb of this._getEventCallbacks(EventType.LABEL_CHANGE)) {
        try {
          cb(detail.change);
        } catch (err) {
          console.error(err);
        }
      }
    },

    modifyRevertMsg(change, revertMsg, origMsg) {
      for (const cb of this._getEventCallbacks(EventType.REVERT)) {
        try {
          revertMsg = cb(change, revertMsg, origMsg);
        } catch (err) {
          console.error(err);
        }
      }
      return revertMsg;
    },

    getDiffLayers(path, changeNum, patchNum) {
      const layers = [];
      for (const annotationApi of
           this._getEventCallbacks(EventType.ANNOTATE_DIFF)) {
        try {
          const layer = annotationApi.getLayer(path, changeNum, patchNum);
          layers.push(layer);
        } catch (err) {
          console.error(err);
        }
      }
      return layers;
    },

    getLabelValuesPostRevert(change) {
      let labels = {};
      for (const cb of this._getEventCallbacks(EventType.POST_REVERT)) {
        try {
          labels = cb(change);
        } catch (err) {
          console.error(err);
        }
      }
      return labels;
    },

    _getEventCallbacks(type) {
      return this._eventCallbacks[type] || [];
    },
  });
})();
