/*
 * Copyright 2000-2012 JetBrains s.r.o.
 *
 * 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.intellij.openapi.diff.impl.splitter;

import com.intellij.openapi.diff.impl.DiffUtil;
import com.intellij.openapi.diff.impl.EditingSides;
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
import com.intellij.openapi.diff.impl.util.TextDiffType;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.ui.GraphicsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Path2D;
import java.util.ArrayList;

/**
 * A polygon, which is drawn between editors in merge or diff dialogs, and which indicates the change flow from one editor to another.
 */
public class DividerPolygon {

  @Nullable private final Color myColor;
  private final int myStart1;
  private final int myStart2;
  private final int myEnd1;
  private final int myEnd2;
  private final boolean myApplied;

  public static final double CTRL_PROXIMITY_X = 0.3;

  public DividerPolygon(int start1, int start2, int end1, int end2, @Nullable Color color, boolean applied) {
    myApplied = applied;
    myStart1 = advance(start1);
    myStart2 = advance(start2);
    myEnd1 = advance(end1);
    myEnd2 = advance(end2);
    myColor = color;
  }

  private int advance(int y) {
    return y == 0 ? y : y + 1;
  }

  private void paint(Graphics2D g, int width) {
    GraphicsUtil.setupAntialiasing(g);


    if (!myApplied) {
      Shape upperCurve = makeCurve(width, myStart1, myStart2, true);
      Shape lowerCurve = makeCurve(width, myEnd1, myEnd2, false);

      Path2D path = new Path2D.Double();
      path.append(upperCurve, true);
      path.append(lowerCurve, true);
      g.setColor(myColor);
      g.fill(path);

      g.setColor(DiffUtil.getFramingColor(myColor));
      g.draw(upperCurve);
      g.draw(lowerCurve);
    }
    else {
      g.setColor(myColor);
      g.draw(makeCurve(width, myStart1 + 1, myStart2 + 1, true));
      g.draw(makeCurve(width, myStart1 + 2, myStart2 + 2, true));
      g.draw(makeCurve(width, myEnd1 + 1, myEnd2 + 1, false));
      g.draw(makeCurve(width, myEnd1 + 2, myEnd2 + 2, false));
    }
  }

  private static Shape makeCurve(int width, int y1, int y2, boolean forward) {
    if (forward) {
      return new CubicCurve2D.Double(0, y1,
                                     width * CTRL_PROXIMITY_X, y1,
                                     width * (1.0 - CTRL_PROXIMITY_X), y2,
                                     width, y2);
    }
    else {
      return new CubicCurve2D.Double(width, y2,
                                     width * (1.0 - CTRL_PROXIMITY_X), y2,
                                     width * CTRL_PROXIMITY_X, y1,
                                     0, y1);
    }
  }

  public int hashCode() {
    return myStart1 ^ myStart2 ^ myEnd1 ^ myEnd2;
  }

  public boolean equals(Object obj) {
    if (!(obj instanceof DividerPolygon)) return false;
    DividerPolygon other = (DividerPolygon)obj;
    return myStart1 == other.myStart1 &&
           myStart2 == other.myStart2 &&
           myEnd1 == other.myEnd1 &&
           myEnd2 == other.myEnd2 && Comparing.equal(myColor, other.myColor);
  }

  public String toString() {
    return "<" + myStart1 + ", " + myEnd1 + " : " + myStart2 + ", " + myEnd2 + "> " + myColor;
  }

  public Color getColor() {
    return myColor;
  }

  public int getTopLeftY() {
    return myStart1;
  }

  public int getTopRightY() {
    return myStart2;
  }

  public int getBottomLeftY() {
    return myEnd1;
  }

  public int getBottomRightY() {
    return myEnd2;
  }

  public boolean isApplied() {
    return myApplied;
  }

  public static void paintPolygons(ArrayList<DividerPolygon> polygons, Graphics2D g, int width) {
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    //Composite composite = g.getComposite();
    //g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.4f));
    for (DividerPolygon polygon : polygons) {
      polygon.paint(g, width);
    }
    //g.setComposite(composite);
  }

  public static ArrayList<DividerPolygon> createVisiblePolygons(@NotNull EditingSides sides,
                                                                @NotNull FragmentSide left,
                                                                int diffDividerPolygonsOffset) {
    Editor editor1 = sides.getEditor(left);
    Editor editor2 = sides.getEditor(left.otherSide());
    LineBlocks lineBlocks = sides.getLineBlocks();
    Trapezium visibleArea = new Trapezium(getVisibleInterval(editor1),
                                          getVisibleInterval(editor2));
    Interval indices = lineBlocks.getVisibleIndices(visibleArea);
    Transformation[] transformations = new Transformation[]{getTransformation(editor1),
      getTransformation(editor2)};
    ArrayList<DividerPolygon> polygons = new ArrayList<DividerPolygon>();
    for (int i = indices.getStart(); i < indices.getEnd(); i++) {
      Trapezium trapezium = lineBlocks.getTrapezium(i);
      final TextDiffType type = lineBlocks.getType(i);
      Color color = type.getPolygonColor(editor1);
      polygons.add(createPolygon(transformations, trapezium, color, left, diffDividerPolygonsOffset, type.isApplied()));
    }
    return polygons;
  }

  private static Transformation getTransformation(Editor editor) {
//    return new LinearTransformation(editor.getScrollingModel().getVerticalScrollOffset(), editor.getLineHeight());
    return new FoldingTransformation(editor);
  }

  private static DividerPolygon createPolygon(@NotNull Transformation[] transformations,
                                              @NotNull Trapezium trapezium,
                                              @Nullable Color color,
                                              @NotNull FragmentSide left,
                                              int diffDividerPolygonsOffset, boolean applied) {
    Interval base1 = trapezium.getBase(left);
    Interval base2 = trapezium.getBase(left.otherSide());
    Transformation leftTransform = transformations[left.getIndex()];
    Transformation rightTransform = transformations[left.otherSide().getIndex()];
    int start1 = leftTransform.transform(base1.getStart());
    int end1 = leftTransform.transform(base1.getEnd());
    int start2 = rightTransform.transform(base2.getStart());
    int end2 = rightTransform.transform(base2.getEnd());
    return new DividerPolygon(start1 - diffDividerPolygonsOffset, start2 - diffDividerPolygonsOffset,
                              end1 - diffDividerPolygonsOffset, end2 - diffDividerPolygonsOffset,
                              color, applied);
  }

  static Interval getVisibleInterval(Editor editor) {
    int offset = editor.getScrollingModel().getVerticalScrollOffset();
    LogicalPosition logicalPosition = editor.xyToLogicalPosition(new Point(0, offset));
    int line = logicalPosition.line;
    return new Interval(line, editor.getComponent().getHeight() / editor.getLineHeight() + 1);
  }
}
