"use strict";
var au;

if (typeof au === "undefined") {
  au = {};
}

au.getNodeIndex = function(seg) {
  var index = /\[(\d+|last\(\))\]/;
  var match = index.exec(seg);
  if (match) {

    if (match[1].indexOf("last") !== -1) {
      return -1; // last() is internally an index of -1
    }

    // -1 is an invalid index when supplied by the user.
    // set to 0 which is always invalid so parseXpath returns false
    var idx = parseInt(match[1], 10);
    if (idx < 1) {
      idx = 0;
    }

    return idx;
  }
  return null;
};

au.getXpathSearchMethod = function(pathSeg, root) {
  if (typeof root === "undefined") {
    root = false;
  }
  if (root && pathSeg[0] !== "/") {
    return "desc";
  }
  if (pathSeg.substr(0, 2) === "//") {
    return "desc";
  }
  return "child";
};

au.getXpathExtPath = function(matchedExt) {
  var path = [];
  if (matchedExt) {
    // first split on '//'
    matchedExt = matchedExt.replace(/\//g, "|/");
    matchedExt = matchedExt.replace(/\|\/\|\//g, "|//");
    var splits = matchedExt.split("|");
    for (var i = 0; i < splits.length; i++) {
      if (splits[i] !== "") {
        path.push({
          node: splits[i].replace(/\/+/, '').replace(/\[\d+\]/, '')
          , search: au.getXpathSearchMethod(splits[i])
          , index: au.getNodeIndex(splits[i])
        });
      }
    }
  }
  return path;
};

au.parseXpath = function(xpath) {
  // e.g. "//button" or "button" or "/button"
  var index = "(\\[(?:\\d+|last\\(\\))\\])?";
  var root = "^(/?/?(?:[a-zA-Z]+|\\*)" + index + ")";
  var ext = "((//?[a-zA-Z]+" + index + ")*)"; // e.g. "/text" or "/cell//button/text"
  var attrEq = "(@[a-zA-Z0-9_]+=[^\\]]+)"; // e.g. [@name="foo"]
  // e.g. [contains(@name, "foo")]
  var attrContains = "(contains\\(@[a-zA-Z0-9_]+, ?[^\\]]+\\))";
  var attr = "(\\[(" + attrEq + "|" + attrContains + ")\\])?$";
  var xpathRe = new RegExp(root + ext + attr); // all together now
  var match = xpathRe.exec(xpath);
  if (match) {
    var matchedRoot = match[1]
      , matchedExt = match[3]
      , matchedAttrEq = match[8]
      , matchedContains = match[9]
      , attrName = null
      , attrConstraint = null
      , substrMatch = false
      , path = []
      , rootSearch = au.getXpathSearchMethod(matchedRoot, true)
      , parts = null;
    path.push({
      node: matchedRoot.replace(/\/+/, '').replace(/\[\d+\]/, '').replace(/\[last\(\)\]/, '')
      , search: rootSearch
      , index: au.getNodeIndex(matchedRoot)
    });
    path = path.concat(au.getXpathExtPath(matchedExt));
    if (matchedAttrEq || matchedContains) {
      if (matchedAttrEq) {
        parts = matchedAttrEq.split("=");
        attrName = parts[0].substr(1);
      } else if (matchedContains) {
        substrMatch = true;
        parts = matchedContains.split(",");
        attrName = parts[0].substr(10);
        parts[1] = parts[1].substr(0, parts[1].length - 1);
        parts[1] = parts[1].replace(/^ /, '');
      }
      if (parts[1][0] === "'" || parts[1][0] === '"') {
        attrConstraint = parts[1].substr(1, parts[1].length - 2);
      } else {
        attrConstraint = parts[1];
      }
    }

    // ensure we're using 1-indexing
    for (var i = 0; i < path.length; i++) {
      if (path[i].index !== null && path[i].index < 1 && path[i].index !== -1) {
        return false;
      }
    }
    var ret = {
      path: path
      , attr: attrName
      , constraint: attrConstraint
      , substr: substrMatch
    };
    return ret;
  } else {
    return false;
  }
};

if (typeof module !== "undefined") {
  module.exports = au;
}
