// Copyright (C) 2013 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.

package com.google.gerrit.client.diff;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;

import net.codemirror.lib.CodeMirror;

import java.util.PriorityQueue;

/**
 * LineWidget attached to a CodeMirror container.
 *
 * When a comment is placed on a line a CommentWidget is created on both sides.
 * The group tracks all comment boxes on that same line, and also includes an
 * empty padding element to keep subsequent lines vertically aligned.
 */
class SideBySideCommentGroup extends CommentGroup
    implements Comparable<SideBySideCommentGroup> {
  static void pair(SideBySideCommentGroup a, SideBySideCommentGroup b) {
    a.peers.add(b);
    b.peers.add(a);
  }

  private final Element padding;
  private final PriorityQueue<SideBySideCommentGroup> peers;

  SideBySideCommentGroup(SideBySideCommentManager manager, CodeMirror cm, DisplaySide side,
      int line) {
    super(manager, cm, side, line);

    padding = DOM.createDiv();
    padding.setClassName(SideBySideTable.style.padding());
    SideBySideChunkManager.focusOnClick(padding, cm.side());
    getElement().appendChild(padding);
    peers = new PriorityQueue<>();
  }

  SideBySideCommentGroup getPeer() {
    return peers.peek();
  }

  @Override
  void remove(DraftBox box) {
    super.remove(box);

    if (getBoxCount() == 0 && peers.size() == 1
        && peers.peek().peers.size() > 1) {
      SideBySideCommentGroup peer = peers.peek();
      peer.peers.remove(this);
      detach();
      if (peer.getBoxCount() == 0 && peer.peers.size() == 1
          && peer.peers.peek().getBoxCount() == 0) {
        peer.detach();
      } else {
        peer.resize();
      }
    } else {
      resize();
    }
  }

  @Override
  void init(DiffTable parent) {
    if (getLineWidget() == null) {
      attach(parent);
    }
    for (CommentGroup peer : peers) {
      if (peer.getLineWidget() == null) {
        peer.attach(parent);
      }
    }
  }

  @Override
  void handleRedraw() {
    getLineWidget().onRedraw(new Runnable() {
      @Override
      public void run() {
        if (canComputeHeight() && peers.peek().canComputeHeight()) {
          if (getResizeTimer() != null) {
            getResizeTimer().cancel();
            setResizeTimer(null);
          }
          adjustPadding(SideBySideCommentGroup.this, peers.peek());
        } else if (getResizeTimer() == null) {
          setResizeTimer(new Timer() {
            @Override
            public void run() {
              if (canComputeHeight() && peers.peek().canComputeHeight()) {
                cancel();
                setResizeTimer(null);
                adjustPadding(SideBySideCommentGroup.this, peers.peek());
              }
            }
          });
          getResizeTimer().scheduleRepeating(5);
        }
      }
    });
  }

  @Override
  void resize() {
    if (getLineWidget() != null) {
      adjustPadding(this, peers.peek());
    }
  }

  private int computeHeight() {
    if (getComments().isVisible()) {
      // Include margin-bottom: 5px from CSS class.
      return getComments().getOffsetHeight() + 5;
    }
    return 0;
  }

  private static void adjustPadding(SideBySideCommentGroup a, SideBySideCommentGroup b) {
    int apx = a.computeHeight();
    int bpx = b.computeHeight();
    for (SideBySideCommentGroup otherPeer : a.peers) {
      if (otherPeer != b) {
        bpx += otherPeer.computeHeight();
      }
    }
    for (SideBySideCommentGroup otherPeer : b.peers) {
      if (otherPeer != a) {
        apx += otherPeer.computeHeight();
      }
    }
    int h = Math.max(apx, bpx);
    a.padding.getStyle().setHeight(Math.max(0, h - apx), Unit.PX);
    b.padding.getStyle().setHeight(Math.max(0, h - bpx), Unit.PX);
    a.getLineWidget().changed();
    b.getLineWidget().changed();
    a.updateSelection();
    b.updateSelection();
  }

  @Override
  public int compareTo(SideBySideCommentGroup o) {
    if (side == o.side) {
      return line - o.line;
    }
    throw new IllegalStateException(
        "Cannot compare SideBySideCommentGroup with different sides");
  }
}
