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

  Polymer({
    is: 'gr-related-changes-list',

    properties: {
      change: Object,
      hasParent: {
        type: Boolean,
        notify: true,
        value: false,
      },
      patchNum: String,
      parentChange: Object,
      hidden: {
        type: Boolean,
        value: false,
        reflectToAttribute: true,
      },
      loading: {
        type: Boolean,
        notify: true,
      },
      _connectedRevisions: {
        type: Array,
        computed: '_computeConnectedRevisions(change, patchNum, ' +
            '_relatedResponse.changes)',
      },
      /** @type {?} */
      _relatedResponse: {
        type: Object,
        value() { return {changes: []}; },
      },
      _submittedTogether: {
        type: Array,
        value() { return []; },
      },
      _conflicts: {
        type: Array,
        value() { return []; },
      },
      _cherryPicks: {
        type: Array,
        value() { return []; },
      },
      _sameTopic: {
        type: Array,
        value() { return []; },
      },
    },

    behaviors: [
      Gerrit.PatchSetBehavior,
      Gerrit.RESTClientBehavior,
    ],

    observers: [
      '_resultsChanged(_relatedResponse.changes, _submittedTogether, ' +
          '_conflicts, _cherryPicks, _sameTopic)',
    ],

    clear() {
      this.loading = true;
      this.hidden = true;
    },

    reload() {
      if (!this.change || !this.patchNum) {
        return Promise.resolve();
      }
      this.loading = true;
      const promises = [
        this._getRelatedChanges().then(response => {
          this._relatedResponse = response;

          this.hasParent = this._calculateHasParent(this.change.change_id,
              response.changes);
        }),
        this._getSubmittedTogether().then(response => {
          this._submittedTogether = response;
        }),
        this._getCherryPicks().then(response => {
          this._cherryPicks = response;
        }),
      ];

      // Get conflicts if change is open and is mergeable.
      if (this.changeIsOpen(this.change.status) && this.change.mergeable) {
        promises.push(this._getConflicts().then(response => {
          // Because the server doesn't always return a response and the
          // template expects an array, always return an array.
          this._conflicts = response ? response : [];
        }));
      }

      promises.push(this._getServerConfig().then(config => {
        if (this.change.topic && !config.change.submit_whole_topic) {
          return this._getChangesWithSameTopic().then(response => {
            this._sameTopic = response;
          });
        } else {
          this._sameTopic = [];
        }
        return this._sameTopic;
      }));

      return Promise.all(promises).then(() => {
        this.loading = false;
      });
    },

    /**
     * Determines whether or not the given change has a parent change. If there
     * is a relation chain, and the change id is not the last item of the
     * relation chain, there is a parent.
     * @param  {number} currentChangeId
     * @param  {!Array} relatedChanges
     * @return {boolean}
     */
    _calculateHasParent(currentChangeId, relatedChanges) {
      return relatedChanges.length > 0 &&
          relatedChanges[relatedChanges.length - 1].change_id !==
          currentChangeId;
    },

    _getRelatedChanges() {
      return this.$.restAPI.getRelatedChanges(this.change._number,
          this.patchNum);
    },

    _getSubmittedTogether() {
      return this.$.restAPI.getChangesSubmittedTogether(this.change._number);
    },

    _getServerConfig() {
      return this.$.restAPI.getConfig();
    },

    _getConflicts() {
      return this.$.restAPI.getChangeConflicts(this.change._number);
    },

    _getCherryPicks() {
      return this.$.restAPI.getChangeCherryPicks(this.change.project,
          this.change.change_id, this.change._number);
    },

    _getChangesWithSameTopic() {
      return this.$.restAPI.getChangesWithSameTopic(this.change.topic,
          this.change._number);
    },

    /**
     * @param {number} changeNum
     * @param {string} project
     * @param {number=} opt_patchNum
     * @return {string}
     */
    _computeChangeURL(changeNum, project, opt_patchNum) {
      return Gerrit.Nav.getUrlForChangeById(changeNum, project, opt_patchNum);
    },

    _computeChangeContainerClass(currentChange, relatedChange) {
      const classes = ['changeContainer'];
      if (relatedChange.change_id === currentChange.change_id) {
        classes.push('thisChange');
      }
      return classes.join(' ');
    },

    _computeLinkClass(change) {
      const statuses = [];
      if (change.status == this.ChangeStatus.ABANDONED) {
        statuses.push('strikethrough');
      }
      if (change.submittable) {
        statuses.push('submittable');
      }
      return statuses.join(' ');
    },

    _computeChangeStatusClass(change) {
      const classes = ['status'];
      if (change._revision_number != change._current_revision_number) {
        classes.push('notCurrent');
      } else if (this._isIndirectAncestor(change)) {
        classes.push('indirectAncestor');
      } else if (change.submittable) {
        classes.push('submittable');
      } else if (change.status == this.ChangeStatus.NEW) {
        classes.push('hidden');
      }
      return classes.join(' ');
    },

    _computeChangeStatus(change) {
      switch (change.status) {
        case this.ChangeStatus.MERGED:
          return 'Merged';
        case this.ChangeStatus.ABANDONED:
          return 'Abandoned';
      }
      if (change._revision_number != change._current_revision_number) {
        return 'Not current';
      } else if (this._isIndirectAncestor(change)) {
        return 'Indirect ancestor';
      } else if (change.submittable) {
        return 'Submittable';
      }
      return '';
    },

    _resultsChanged(related, submittedTogether, conflicts,
        cherryPicks, sameTopic) {
      const results = [
        related,
        submittedTogether,
        conflicts,
        cherryPicks,
        sameTopic,
      ];
      for (let i = 0; i < results.length; i++) {
        if (results[i].length > 0) {
          this.hidden = false;
          this.fire('update', null, {bubbles: false});
          return;
        }
      }
      this.hidden = true;
    },

    _isIndirectAncestor(change) {
      return !this._connectedRevisions.includes(change.commit.commit);
    },

    _computeConnectedRevisions(change, patchNum, relatedChanges) {
      const connected = [];
      let changeRevision;
      for (const rev in change.revisions) {
        if (this.patchNumEquals(change.revisions[rev]._number, patchNum)) {
          changeRevision = rev;
        }
      }
      const commits = relatedChanges.map(c => { return c.commit; });
      let pos = commits.length - 1;

      while (pos >= 0) {
        const commit = commits[pos].commit;
        connected.push(commit);
        if (commit == changeRevision) {
          break;
        }
        pos--;
      }
      while (pos >= 0) {
        for (let i = 0; i < commits[pos].parents.length; i++) {
          if (connected.includes(commits[pos].parents[i].commit)) {
            connected.push(commits[pos].commit);
            break;
          }
        }
        --pos;
      }
      return connected;
    },
  });
})();
