/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.
 */

/**
 * @author Jorge Bay Gondra
 */
'use strict';

const utils = require('../utils');
const itemDone = Object.freeze({ value: null, done: true });
const asyncIteratorSymbol = Symbol.asyncIterator || Symbol('@@asyncIterator');

class Traversal {
  constructor(graph, traversalStrategies, bytecode) {
    this.graph = graph;
    this.traversalStrategies = traversalStrategies;
    this.bytecode = bytecode;
    /** @type {Array<Traverser>} */
    this.traversers = null;
    this.sideEffects = null;
    this._traversalStrategiesPromise = null;
    this._traversersIteratorIndex = 0;
  }

  /**
   * Async iterable method implementation.
   */
  [asyncIteratorSymbol]() {
    return this;
  }

  /** @returns {Bytecode} */
  getBytecode() {
    return this.bytecode;
  }

  /**
   * Returns an Array containing the traverser objects.
   * @returns {Promise.<Array>}
   */
  toList() {
    return this._applyStrategies().then(() => {
      const result = [];
      let it;
      while ((it = this._getNext()) && !it.done) {
        result.push(it.value);
      }
      return result;
    });
  };

  /**
   * Determines if there are any more items to iterate from the traversal.
   * @returns {Promise.<boolean>}
   */
   hasNext() {
     return this._applyStrategies().then(() => {
       return this.traversers && this.traversers.length > 0 &&
              this._traversersIteratorIndex < this.traversers.length &&
              this.traversers[this._traversersIteratorIndex].bulk > 0;
     });
   }

  /**
   * Iterates all Traverser instances in the traversal.
   * @returns {Promise}
   */
  iterate() {
    this.bytecode.addStep('none');
    return this._applyStrategies().then(() => {
      let it;
      while ((it = this._getNext()) && !it.done) {
      }
    });
  }

  /**
   * Async iterator method implementation.
   * Returns a promise containing an iterator item.
   * @returns {Promise.<{value, done}>}
   */
  next() {
    return this._applyStrategies().then(() => this._getNext());
  }

  /**
   * Synchronous iterator of traversers including
   * @private
   */
  _getNext() {
    while (this.traversers && this._traversersIteratorIndex < this.traversers.length) {
      let traverser = this.traversers[this._traversersIteratorIndex];
      if (traverser.bulk > 0) {
        traverser.bulk--;
        return { value: traverser.object, done: false };
      }
      this._traversersIteratorIndex++;
    }
    return itemDone;
  }

  _applyStrategies() {
    if (this._traversalStrategiesPromise) {
      // Apply strategies only once
      return this._traversalStrategiesPromise;
    }
    return this._traversalStrategiesPromise = this.traversalStrategies.applyStrategies(this);
  }

  /**
   * Returns step instructions during JSON serialization
   * @returns {Array}
   */
  toJSON(){
    return this.bytecode.stepInstructions;
  }

  /**
   * Returns the Bytecode JSON representation of the traversal
   * @returns {String}
   */
  toString() {
    return this.bytecode.toString();
  };
}

<% tokens.each { k,v -> %>
class <%= k %> {
<% v.each {a,b -> %>
 static get <%= a %>() {
   return "<%= b %>"
 }
<% } %>}
<% } %>

class P {
  /**
   * Represents an operation.
   * @constructor
   */
  constructor(operator, value, other) {
    this.operator = operator;
    this.value = value;
    this.other = other;
  }

  /**
   * Returns the string representation of the instance.
   * @returns {string}
   */
  toString() {
    function formatValue(value){
      if (Array.isArray(value)) {
        let acc = [];
        for (const item of value) {
          acc.push(formatValue(item));
        }
        return acc;
      }
      if (value && typeof value === "string"){
        return "'" + value + "'";
      }
      return value;
    }

    if (this.other === undefined || this.other === null) {
      return this.operator + '(' + formatValue(this.value) + ')';
    }
    return this.operator + '(' + formatValue(this.value) + ', ' + formatValue(this.other) + ')';
  }

  and(arg) {
    return new P('and', this, arg);
  }

  or(arg) {
    return new P('or', this, arg);
  }

  static within(...args) {
    if (args.length === 1 && Array.isArray(args[0])) {
      return new P("within", args[0], null);
    } else {
      return new P("within", args, null);
    }
  }

  static without(...args) {
    if (args.length === 1 && Array.isArray(args[0])) {
      return new P("without", args[0], null);
    } else {
      return new P("without", args, null);
    }
  }

<% pmethods.findAll{!(it in ["within","without"])}.each{ method -> %>
  /** @param {...Object} args */
  static <%= toJs.call(method) %>(...args) {
    return createP('<%= method %>', args);
  }
<% } %>
}

function createP(operator, args) {
  args.unshift(null, operator);
  return new (Function.prototype.bind.apply(P, args));
}

class TextP {
  /**
   * Represents an operation.
   * @constructor
   */
  constructor(operator, value, other) {
    this.operator = operator;
    this.value = value;
    this.other = other;
  }

  /**
   * Returns the string representation of the instance.
   * @returns {string}
   */
  toString() {
    function formatValue(value){
      if (value && typeof value === "string"){
        return "'" + value + "'";
      }
      return value;
    }

    if (this.other === undefined) {
      return this.operator + '(' + formatValue(this.value) + ')';
    }
    return this.operator + '(' + formatValue(this.value) + ', ' + formatValue(this.other) + ')';
  }

  and(arg) {
    return new P('and', this, arg);
  }

  or(arg) {
    return new P('or', this, arg);
  }
<% tpmethods.each{ method -> %>
  /** @param {...Object} args */
  static <%= toJs.call(method) %>(...args) {
    return createTextP('<%= method %>', args);
  }
<% } %>
}

function createTextP(operator, args) {
  args.unshift(null, operator);
  return new (Function.prototype.bind.apply(TextP, args));
}

class Traverser {
  constructor(object, bulk) {
    this.object = object;
    this.bulk = bulk || 1;
  }
}

class TraversalSideEffects {

}

const withOptions = {
  <%= withOptions.collect { it.name + ": " + it.value }.join(",\n  ")%>
};

function toEnum(typeName, keys) {
  const result = {};
  keys.split(' ').forEach(k => {
    let jsKey = k;
    if (jsKey === jsKey.toUpperCase()) {
      jsKey = jsKey.toLowerCase();
    }
    result[jsKey] = new EnumValue(typeName, k);
  });
  return result;
}

class EnumValue {
  constructor(typeName, elementName) {
    this.typeName = typeName;
    this.elementName = elementName;
  }

  toString() {
    return this.elementName;
  }
}

module.exports = {
  EnumValue,
  P,
  TextP,
  withOptions,
  IO,
  Traversal,
  TraversalSideEffects,
  Traverser<%
enums.each{ enumClass ->
    out.print ",\n  " + decapitalize.call(enumClass.simpleName) + ": toEnum('" + enumClass.simpleName + "', '" +
        enumClass.getEnumConstants().sort { a, b -> a.name() <=> b.name() }.collect { toJs.call(it.name()) }.join(' ') + "')"
}
%>
};
