'use strict';

const keywords = new Map();
const properties = new Map();
const HYPHENMINUS = 45; // '-'.charCodeAt()

const keyword = getKeywordDescriptor;
const property = getPropertyDescriptor;
const vendorPrefix = getVendorPrefix;
function isCustomProperty(str, offset) {
  offset = offset || 0;

  return (
    str.length - offset >= 2 &&
    str.charCodeAt(offset) === HYPHENMINUS &&
    str.charCodeAt(offset + 1) === HYPHENMINUS
  );
}

function getVendorPrefix(str, offset) {
  offset = offset || 0;

  // verdor prefix should be at least 3 chars length
  if (str.length - offset >= 3) {
    // vendor prefix starts with hyper minus following non-hyper minus
    if (
      str.charCodeAt(offset) === HYPHENMINUS &&
      str.charCodeAt(offset + 1) !== HYPHENMINUS
    ) {
      // vendor prefix should contain a hyper minus at the ending
      const secondDashIndex = str.indexOf('-', offset + 2);

      if (secondDashIndex !== -1) {
        return str.substring(offset, secondDashIndex + 1);
      }
    }
  }

  return '';
}

function getKeywordDescriptor(keyword) {
  if (keywords.has(keyword)) {
    return keywords.get(keyword);
  }

  const name = keyword.toLowerCase();
  let descriptor = keywords.get(name);

  if (descriptor === undefined) {
    const custom = isCustomProperty(name, 0);
    const vendor = !custom ? getVendorPrefix(name, 0) : '';
    descriptor = Object.freeze({
      basename: name.substr(vendor.length),
      name,
      prefix: vendor,
      vendor,
      custom,
    });
  }

  keywords.set(keyword, descriptor);

  return descriptor;
}

function getPropertyDescriptor(property) {
  if (properties.has(property)) {
    return properties.get(property);
  }

  let name = property;
  let hack = property[0];

  if (hack === '/') {
    hack = property[1] === '/' ? '//' : '/';
  } else if (
    hack !== '_' &&
    hack !== '*' &&
    hack !== '$' &&
    hack !== '#' &&
    hack !== '+' &&
    hack !== '&'
  ) {
    hack = '';
  }

  const custom = isCustomProperty(name, hack.length);

  // re-use result when possible (the same as for lower case)
  if (!custom) {
    name = name.toLowerCase();
    if (properties.has(name)) {
      const descriptor = properties.get(name);
      properties.set(property, descriptor);
      return descriptor;
    }
  }

  const vendor = !custom ? getVendorPrefix(name, hack.length) : '';
  const prefix = name.substr(0, hack.length + vendor.length);
  const descriptor = Object.freeze({
    basename: name.substr(prefix.length),
    name: name.substr(hack.length),
    hack,
    vendor,
    prefix,
    custom,
  });

  properties.set(property, descriptor);

  return descriptor;
}

exports.isCustomProperty = isCustomProperty;
exports.keyword = keyword;
exports.property = property;
exports.vendorPrefix = vendorPrefix;