// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

"use strict";

class CodeView extends View {
  constructor(divID, PR, sourceText, sourcePosition, broker) {
    super(divID, broker, null, false);
    let view = this;
    view.PR = PR;
    view.mouseDown = false;
    view.broker = broker;
    view.allSpans = [];

    var selectionHandler = {
      clear: function() { broker.clear(selectionHandler); },
      select: function(items, selected) {
        var handler = this;
        var broker = view.broker;
        for (let span of items) {
          if (selected) {
            span.classList.add("selected");
          } else {
            span.classList.remove("selected");
          }
        }
        var locations = [];
        for (var span of items) {
          locations.push({pos_start: span.start, pos_end: span.end});
        }
        broker.clear(selectionHandler);
        broker.select(selectionHandler, locations, selected);
      },
      selectionDifference: function(span1, inclusive1, span2, inclusive2) {
        var pos1 = span1.start;
        var pos2 = span2.start;
        var result = [];
        var lineListDiv = view.divNode.firstChild.firstChild.childNodes;
        for (var i = 0; i < lineListDiv.length; i++) {
          var currentLineElement = lineListDiv[i];
          var spans = currentLineElement.childNodes;
          for (var j = 0; j < spans.length; ++j) {
            var currentSpan = spans[j];
            if (currentSpan.start > pos1 ||
                (inclusive1 && currentSpan.start == pos1)) {
              if (currentSpan.start < pos2 ||
                  (inclusive2 && currentSpan.start == pos2)) {
                result.push(currentSpan);
              }
            }
          }
        }
        return result;
      },
      brokeredSelect: function(locations, selected) {
        let firstSelect = view.selection.isEmpty();
        for (let location of locations) {
          let start = location.pos_start;
          let end = location.pos_end;
          if (start && end) {
            let lower = 0;
            let upper = view.allSpans.length;
            if (upper > 0) {
              while ((upper - lower) > 1) {
                var middle = Math.floor((upper + lower) / 2);
                var lineStart = view.allSpans[middle].start;
                if (lineStart < start) {
                  lower = middle;
                } else if (lineStart > start) {
                  upper = middle;
                } else {
                  lower = middle;
                  break;
                }
              }
              var currentSpan = view.allSpans[lower];
              var currentLineElement = currentSpan.parentNode;
              if ((currentSpan.start <= start && start < currentSpan.end) ||
                  (currentSpan.start <= end && end < currentSpan.end)) {
                if (firstSelect) {
                  makeContainerPosVisible(
                      view.divNode, currentLineElement.offsetTop);
                  firstSelect = false;
                }
                view.selection.select(currentSpan, selected);
              }
            }
          }
        }
      },
      brokeredClear: function() { view.selection.clear(); },
    };
    view.selection = new Selection(selectionHandler);
    broker.addSelectionHandler(selectionHandler);

    view.handleSpanMouseDown = function(e) {
      e.stopPropagation();
      if (!e.shiftKey) {
        view.selection.clear();
      }
      view.selection.select(this, true);
      view.mouseDown = true;
    }

    view.handleSpanMouseMove = function(e) {
      if (view.mouseDown) {
        view.selection.extendTo(this);
      }
    }

    view.handleCodeMouseDown = function(e) { view.selection.clear(); }

    document.addEventListener('mouseup', function(e) {
      view.mouseDown = false;
    }, false);

    view.initializeCode(sourceText, sourcePosition);
  }

  initializeContent(data, rememberedSelection) { this.data = data; }

  initializeCode(sourceText, sourcePosition) {
    var view = this;
    if (sourceText == "") {
      var newHtml = "<pre class=\"prettyprint\"</pre>";
      view.divNode.innerHTML = newHtml;
    } else {
      var newHtml =
          "<pre class=\"prettyprint linenums\">" + sourceText + "</pre>";
      view.divNode.innerHTML = newHtml;
      try {
        // Wrap in try to work when offline.
        view.PR.prettyPrint();
      } catch (e) {
      }

      view.divNode.onmousedown = this.handleCodeMouseDown;

      var base = sourcePosition;
      var current = 0;
      var lineListDiv = view.divNode.firstChild.firstChild.childNodes;
      for (let i = 0; i < lineListDiv.length; i++) {
        var currentLineElement = lineListDiv[i];
        currentLineElement.id = "li" + i;
        var pos = base + current;
        currentLineElement.pos = pos;
        var spans = currentLineElement.childNodes;
        for (let j = 0; j < spans.length; ++j) {
          var currentSpan = spans[j];
          if (currentSpan.nodeType == 1) {
            currentSpan.start = pos;
            currentSpan.end = pos + currentSpan.textContent.length;
            currentSpan.onmousedown = this.handleSpanMouseDown;
            currentSpan.onmousemove = this.handleSpanMouseMove;
            view.allSpans.push(currentSpan);
          }
          current += currentSpan.textContent.length;
          pos = base + current;
        }
        while ((current < sourceText.length) &&
               (sourceText[current] == '\n' || sourceText[current] == '\r')) {
          ++current;
        }
      }
    }

    view.resizeToParent();
  }

  deleteContent() {}
}