// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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.collide.client.filehistory;

import collide.client.util.Elements;

import com.google.collide.client.AppContext;
import com.google.collide.client.code.FileContent;
import com.google.collide.client.code.FileSelectedPlace;
import com.google.collide.client.history.Place;
import com.google.collide.client.util.PathUtil;
import com.google.collide.client.workspace.WorkspacePlace;
import com.google.collide.mvp.CompositeView;
import com.google.collide.mvp.UiComponent;
import com.google.common.annotations.VisibleForTesting;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiTemplate;

import elemental.dom.Element;
import elemental.events.Event;
import elemental.events.EventListener;


/**
 * The File History diff and bar view, which uses a Javascript timeline widget
 * to compare past revisions. Also allows for reverting back to previous
 * revisions.
 *
 */
public class FileHistory extends UiComponent<FileHistory.View> implements FileContent {

  /**
   * Static factory method for obtaining an instance of FileHistory.
   */
  public static FileHistory create(
      Place currentPlace, AppContext appContext, FileHistory.View view) {
    return new FileHistory(view, currentPlace, appContext);
  }

  public interface Css extends CssResource {
    String base();

    String diff();

    String timelineBar();

    String timelineWrapper();

    String timelineTitle();

    String filters();

    String filter();

    String currentFilter();

    String closeButton();

    String closeIcon();

    String button();

    String disabledButton();

    String title();

    String rightRevisionTitle();

    String leftRevisionTitle();

    String titleBar();
  }

  public interface Resources extends Timeline.Resources {
    @Source("close.png")
    ImageResource closeIcon();

    @Source("FileHistory.css")
    Css fileHistoryCss();
  }

  public static class View extends CompositeView<ViewEvents> {
    @UiTemplate("FileHistory.ui.xml")
    interface MyBinder extends UiBinder<com.google.gwt.dom.client.DivElement, View> {
    }

    static MyBinder binder = GWT.create(MyBinder.class);

    @UiField
    DivElement diff;

    @UiField
    DivElement timelineBar;

    @UiField
    DivElement timelineWrapper;

    @UiField
    DivElement timelineTitle;

    Element leftRevisionTitle;

    Element rightRevisionTitle;

    Element titleBar;

    Element closeButton;

    Element closeIcon;

    Timeline.View timelineView;

    @UiField(provided = true)
    final Resources res;

    @UiField(provided = true)
    final Css css;

    View(Resources res) {
      this.res = res;
      this.css = res.fileHistoryCss();
      this.timelineView = new Timeline.View(res);

      setElement(Elements.asJsElement(binder.createAndBindUi(this)));

      Elements.asJsElement(timelineWrapper).appendChild(timelineView.getElement());
      createDom();

      attachEventHandlers();
    }

    protected void attachEventHandlers() {
      closeButton.setOnclick(new EventListener() {
        @Override
        public void handleEvent(Event evt) {
          ViewEvents delegate = getDelegate();
          if (delegate == null) {
            return;
          }
          delegate.onCloseButtonClicked();
        }
      });

    }

    /**
     * Initialize diff revision titles on the toolbar (default to base version
     * and current version.
     */
    private void createDom() {
      closeButton = Elements.createDivElement(css.closeButton());
      closeIcon = Elements.createDivElement(css.closeIcon());

      closeButton.appendChild(closeIcon);

      titleBar = Elements.createDivElement(css.titleBar());
      leftRevisionTitle = Elements.createDivElement(css.leftRevisionTitle());
      rightRevisionTitle = Elements.createDivElement(css.rightRevisionTitle());

      leftRevisionTitle.addClassName(css.title());
      rightRevisionTitle.addClassName(css.title());

      titleBar.appendChild(leftRevisionTitle);
      titleBar.appendChild(rightRevisionTitle);

    }

  }

  /**
   * Events reported by the FileHistory's View.
   */
  private interface ViewEvents {
    void onCloseButtonClicked();
  }

  /**
   * The delegate implementation for handling events reported by the View.
   */
  private class ViewEventsImpl implements ViewEvents {

    @Override
    public void onCloseButtonClicked() {
      // Clear editor content
      api.clearDiffEditors();

      // unfortunately this must be hard coded since we can be either a child of
      // the file selected place or the workspace place.
      WorkspacePlace.PLACE.fireChildPlaceNavigation(
          FileSelectedPlace.PLACE.createNavigationEvent(path));
    }
  }

  private final AppContext appContext;
  private final Place currentPlace;
  private PathUtil path;
  private FileHistoryApi api;

  @VisibleForTesting
  protected FileHistory(View view, Place currentPlace, AppContext appContext) {
    super(view);
    this.currentPlace = currentPlace;
    this.appContext = appContext;
    this.path = PathUtil.WORKSPACE_ROOT;

    view.setDelegate(new ViewEventsImpl());
  }

  @Override
  public PathUtil filePath() {
    return path;
  }
  
  public void setPath(PathUtil path) {
    this.path = path;
  }

  public void setApi(FileHistoryApi api) {
    this.api = api;
  }

  @Override
  public Element getContentElement() {
    return getView().getElement();
  }

  @Override
  public void onContentDisplayed() {
  }

  @Override
  public void onContentDestroyed() {

  }

  /* Setup/teardown for the FileHistory place */
  public void setup(Element contentHeader) {
    contentHeader.appendChild(getView().closeButton);
    contentHeader.appendChild(getView().titleBar);

    changeLeftRevisionTitle("Workspace Branched");
    changeRightRevisionTitle("Current Version");
  }

  public void teardown() {
    getView().closeButton.removeFromParent();
    getView().titleBar.removeFromParent();
  }

  /* Change revision titles */

  public void changeLeftRevisionTitle(String title) {
    getView().leftRevisionTitle.setTextContent(title);
  }

  public void changeRightRevisionTitle(String title) {
    getView().rightRevisionTitle.setTextContent(title);
  }
}
