/**
 * Silex, live web creation
 * http://projects.silexlabs.org/?/silex/
 *
 * Copyright (c) 2012 Silex Labs
 * http://www.silexlabs.org/
 *
 * Silex is available under the GPL license
 * http://www.silexlabs.org/silex/silex-licensing/
 */

/**
 * @fileoverview The Silex PageTool class displays the list of pages
 *     and let the user interact with them.
 * @see silex.model.Page
 *
 */

import { PageData } from '../model/page';
import { Controller, Model } from '../types';
import { Dom } from '../utils/dom';
import { InvalidationManager } from '../utils/invalidation-manager';

/**
 *
 * @param element   container to render the UI
 * @param model  model class which holds
 * the model instances - views use it for read
 * operation only
 * @param controller  structure which holds
 * the controller instances
 */
export class PageTool {
  /**
   * page list based on what is passed to redraw
   * array of pages for the opened website
   * @see silex.model.PageData
   */
  pages: PageData[] = [];

  /**
   * invalidation mechanism
   */
  invalidationManager: InvalidationManager;

  constructor(public element: HTMLElement, public model: Model, public controller: Controller) {
    this.invalidationManager = new InvalidationManager(500);
  }

  /**
   * add listeners on the tool container
   * called by the app constructor
   */
  buildUi() {
    // listen for the click on a page
    this.element.addEventListener('click', (e) => {
      if ((e.target as HTMLElement).classList.contains('delete')) {
        // remove the page
        this.removePageAtIndex(
            this.getCellIndex((e.target as HTMLElement).parentElement.parentElement as HTMLElement));
      } else {
        if ((e.target as HTMLElement).classList.contains('label')) {
          // rename the page
          this.renamePageAtIndex(
              this.getCellIndex((e.target as HTMLElement).parentElement.parentElement as HTMLElement));
        } else {
          // select page
          const cellIndex = this.getCellIndex((e.target as HTMLElement).parentElement as HTMLElement);
          if (cellIndex >= 0) {
            this.setSelectedIndex(cellIndex, true);
          }
        }
      }
      e.preventDefault();
    }, false);

    function attach(className, cbk) {
      Array.from(document.querySelectorAll(className))
      .forEach((el) => el.onclick = cbk);
    }
    attach(
        '.add-page', (e) => this.controller.insertMenuController.createPage());
    attach(
        '.remove-page', (e) => this.controller.pageToolController.removePage());
    attach(
        '.move-page-up',
        (e) => this.controller.pageToolController.movePageUp());
    attach(
        '.move-page-down',
        (e) => this.controller.pageToolController.movePageDown());
  }

  /**
   * refresh the pages
   * find all pages in the dom
   * @param selectedElements the elements currently selected
   * @param pageNames   the names of the pages which appear in the current HTML file
   * @param  currentPageName   the name of the current page
   */
  redraw(
      selectedElements: HTMLElement[], pageNames: string[],
      currentPageName: string) {
    this.invalidationManager.callWhenReady(() => {
      // prepare the data for the template
      // make an array with name, displayName, linkName and className
      let idx = 0;
      this.pages = pageNames.map((pageName) => {
        const pageElement =
            this.model.file.getContentDocument().getElementById(pageName);
        if (!pageElement) {
          // this happens while undoing or redoing
          return null;
        }
        const res = {
          name: pageName,
          displayName: this.model.file.getContentDocument()
            .getElementById(pageName)
            .innerHTML,
          linkName: '#!' + pageName,
          idx: idx++,
          className: '',
        };
        if (currentPageName === pageName) {
          res.className = 'ui-selected';
        }
        return res;
      });

      // refresh the list with new pages
      const container = this.element.getElementsByClassName('page-tool-container')[0];
      const templateHtml = this.element.getElementsByClassName('page-tool-template')[0].innerHTML;
      container.innerHTML = Dom.renderList(templateHtml, this.pages);
    });
  }

  /**
   * user wants to remove a page
   * @param idx index of the page
   */
  removePageAtIndex(idx: number) {
    this.controller.pageToolController.removePage(this.pages[idx].name);
  }

  /**
   * user wants to rename a page
   * @param idx index of the page
   */
  renamePageAtIndex(idx: number) {
    this.controller.pageToolController.renamePage(this.pages[idx].name);
  }

  /**
   * set the selection of pages
   * @param opt_notify    if true, then notify by calling the onChanged callback
   */
  setSelectedIndex(idx: number, opt_notify?: boolean) {
    // notify the controller
    if (opt_notify) {
      this.controller.pageToolController.openPage(this.pages[idx].name);
    }
  }

  /**
   * get the index of the given cell
   * @param element which represents the cell in the dom
   */
  getCellIndex(element: HTMLElement): number {
    const pageIdx = element.getAttribute('data-page-idx');
    if (pageIdx) {
      return parseInt(pageIdx, 10);
    } else {
      return -1;
    }
  }
}
