/*
 * Copyright 2003-2011 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 jetbrains.mps.nodeEditor.leftHighlighter;

import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import jetbrains.mps.openapi.editor.EditorComponent;
import jetbrains.mps.openapi.editor.cells.CellInfo;
import jetbrains.mps.openapi.editor.cells.CellTraversalUtil;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.openapi.editor.cells.EditorCell_Collection;
import org.jetbrains.annotations.NotNull;

import javax.swing.JScrollBar;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Graphics;

/**
 * User: Alexander Shatalin
 * Date: 02.03.2010
 */
class FoldingButton {
  public static final int HALF_WIDTH = 4;
  private static final int HEIGHT = HALF_WIDTH * 5 / 2;
  private static final int CANT_HEIGHT = HALF_WIDTH * 3 / 2;

  private CellInfo myCellInfo;
  private EditorComponent myEditor;
  private int myY1;
  private int myY2;
  private boolean myIsHidden = false;
  private boolean myIsFolded = false;
  private boolean myMouseOver = false;
  private Color myBackgroundColor;

  FoldingButton(@NotNull EditorCell_Collection cell, @NotNull Color background) {
    //TODO: Can we hold cell directly instad of CellInfo here?
    myCellInfo = cell.getCellInfo();
    assert myCellInfo != null : "CellInfo unavailable for: " + cell;
    myEditor = cell.getEditorComponent();
    myBackgroundColor = background;
  }

  boolean relayout() {
    EditorCell cell = getCell();
    if (cell == null) {
      myIsHidden = true;
      return true;
    }
    if (cell instanceof EditorCell_Collection) {
      EditorCell_Collection collectionCell = (EditorCell_Collection) cell;
      myIsHidden = CellTraversalUtil.getFoldedParent(collectionCell) != null;
      if (!myIsHidden) {
        myIsFolded = collectionCell.isCollapsed();
        EditorCell firstLeafCell = CellTraversalUtil.getFirstLeaf(collectionCell);
        myY1 = firstLeafCell != null ? firstLeafCell.getBaseline() - HEIGHT : collectionCell.getBaseline() - HEIGHT;
        EditorCell lastLeafCell = CellTraversalUtil.getLastLeaf(collectionCell);
        myY2 = lastLeafCell != null ? CellTraversalUtil.getLastLeaf(collectionCell).getBaseline() : collectionCell.getBaseline();
        if (!myIsFolded && myY2 - myY1 < 2 * HEIGHT) {
          // to avoid overlapping folding buttons
          myIsHidden = true;
        }
      }
      return true;
    }
    return false;
  }

  private Color getBorderColor() {
    return myMouseOver
        ? EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR)
        : EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.TEARLINE_COLOR);
  }

  void paintFeedback(Graphics g) {
    if (myMouseOver && !myIsFolded) {
      g.setColor(getBorderColor());
      g.drawLine(0, myY1 + HEIGHT, 0, myY2 - HEIGHT);
    }
  }

  void paint(Graphics g) {
    if (myIsHidden) {
      return;
    }
    Color borderColor = getBorderColor();
    if (!myIsFolded) {
      int xs[] = {-HALF_WIDTH, -HALF_WIDTH, 0, HALF_WIDTH, HALF_WIDTH};
      int ys[] = {myY1, myY1 + CANT_HEIGHT, myY1 + HEIGHT, myY1 + CANT_HEIGHT, myY1};

      g.setColor(myBackgroundColor);
      g.fillPolygon(xs, ys, xs.length);
      g.setColor(borderColor);
      g.drawPolygon(xs, ys, xs.length);

      for (int i = 0; i < xs.length; i++) {
        ys[i] = myY2 - (ys[i] - myY1);
      }

      g.setColor(myBackgroundColor);
      g.fillPolygon(xs, ys, xs.length);
      g.setColor(borderColor);
      g.drawPolygon(xs, ys, xs.length);

      g.setColor(borderColor);
      g.drawLine(-HALF_WIDTH / 2, myY1 + HALF_WIDTH, HALF_WIDTH / 2, myY1 + HALF_WIDTH);
      g.drawLine(-HALF_WIDTH / 2, myY2 - HALF_WIDTH, HALF_WIDTH / 2, myY2 - HALF_WIDTH);

    } else {
      g.setColor(myBackgroundColor);
      g.fillRect(-HALF_WIDTH, myY1, HALF_WIDTH * 2, HALF_WIDTH * 2);

      g.setColor(borderColor);
      g.drawRect(-HALF_WIDTH, myY1, HALF_WIDTH * 2, HALF_WIDTH * 2);

      g.drawLine(-HALF_WIDTH / 2, myY1 + HALF_WIDTH, HALF_WIDTH / 2, myY1 + HALF_WIDTH);
      g.drawLine(0, myY1 + HALF_WIDTH / 2, 0, myY1 + HALF_WIDTH * 3 / 2);
    }
  }

  private EditorCell getCell() {
    return myCellInfo.findCell(myEditor);
  }

  void activate(int x, int y) {
    EditorCell cell = getCell();
    if (cell instanceof EditorCell_Collection) {
      EditorCell_Collection collection = (EditorCell_Collection) cell;
      if (CellTraversalUtil.getFoldedParent(collection) != null) {
        return;
      }
      if (collection.isCollapsed()) {
        collection.unfold();
      } else {
        if (isOnBottomButton(y)) {
          JScrollBar verticalScrollBar = ((jetbrains.mps.nodeEditor.EditorComponent) myEditor).getVerticalScrollBar();
          verticalScrollBar.setValue(Math.max(verticalScrollBar.getValue() - (myY2 - myY1 - HEIGHT), 0));
        }
        collection.fold();
      }
    }
  }

  void mouseEntered(Component component) {
    component.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    myMouseOver = true;
  }

  void mouseExited(Component component) {
    component.setCursor(null);
    myMouseOver = false;
  }

  boolean isInside(int x, int y) {
    if (myIsHidden) {
      return false;
    }
    if (myIsFolded) {
      return Math.abs(x) <= HALF_WIDTH && isOnTopButton(y);
    } else {
      return Math.abs(x) <= HALF_WIDTH && (isOnTopButton(y) || isOnBottomButton(y));
    }
  }

  private boolean isOnTopButton(int y) {
    return myY1 <= y && y <= myY1 + HEIGHT;
  }

  private boolean isOnBottomButton(int y) {
    return myY2 - HEIGHT <= y && y <= myY2;
  }

  int getY() {
    return myY1;
  }

  int getHeight() {
    return myY2 - myY1;
  }
}
