import re
from builtins import object, range
from . import exceptions

class Purl(object):

  def __init__(self, url, **options):
    super(Purl, self).__init__()
    self.param_interpolate = {
      'start': ':',
      'end': ''
    }
    for opt in options:
      if opt == 'interpolate' and len(options[opt]):
        self.setup_interpolate_settings(options[opt])

    split_url     = url.split('?')
    baseurl_split = split_url[0].split('://')

    # protocol and host are required
    if len(baseurl_split) != 2:
      raise exceptions.InvalidUrlError

    host_port_split = Purl.__split_hostname_and_port(baseurl_split[1])

    self._protocol = baseurl_split[0] + '://'
    self._hostname = host_port_split[0]
    self._port     = None
    self._path     = None

    self._params = {}
    self.query    = None
    self._path_compiled = None

    # port + (path)
    if len(host_port_split) == 2:
      port_path = Purl.__split_once(host_port_split[1], '/')
      self._port = ':' + port_path[0]
      if len(port_path) == 2:
        self._path = port_path[1]

      # check port format
      if not Purl.__is_valid_port(self._port):
        raise exceptions.InvalidUrlError

    # hostname + (path)
    else:
      hostname_path = Purl.__split_once(host_port_split[0], '/')
      if len(hostname_path) == 2:
        self._hostname = hostname_path[0]
        self._path     = hostname_path[1]

    if len(self._hostname) < 1:
      raise purl_exc.InvalidUrlError

    # (query)
    try:
      self.query = Purl.__parse_querystring(split_url[1])
    except IndexError:
      self.query = {}

  @staticmethod
  def create_with(options):
    url = ''
    try:
      url = options['protocol'] + options['hostname']
    except KeyError:
      raise exceptions.InvalidUrlError

    if 'port' in options:
      if not Purl.__is_valid_port(options['port']):
        raise exceptions.InvalidUrlError
      url += options['port']
    if 'path' in options:
      url += options['path']

    return Purl(url)

  # check port format
  @staticmethod
  def __is_valid_port(port):
    return not not re.match(r':\d+', port)

  ## url splitting helper
  @staticmethod
  def __split_once(s, target):
    idx = s.find(target)
    if idx >= 0:
      result = []
      result.append(s[:idx])
      result.append(s[idx:])
      return result
    else:
      return [s]

    if len(result) < 1:
      result = None
    elif len(result) == 1:
      result = result[0]
    return result

  ## generate list containing hostname (and port if available)
  @staticmethod
  def __split_hostname_and_port(host_port):
    host_port_split = None
    host_port_match = re.search('[a-zA-Z](:)', host_port)
    if host_port_match:
      border = host_port_match.start(1)
      host_port_split = [
        host_port[0:border],
        host_port[border + 1:]
      ]
    else:
      host_port_split = [host_port]
    return host_port_split

  def setup_interpolate_settings(self, options):
    if isinstance(options, str):
      self.param_interpolate['start'] = options
    else:
      self.param_interpolate['start'] = options[0]
      if len(options) == 2:
        self.param_interpolate['end'] = options[1]

  ## update query
  def add_query(self, query, value=None):
    if value is None:
      for k in query:
        self.add_query(k, query[k])
    else:
      self.query[query] = value
    return self

  ## delete keys from query
  def delete_query(self, query):
    if isinstance(query, list):
      for k in query:
        Purl.__del_dict(self.query, k)
    else:
      Purl.__del_dict(self.query, query)
    return self

  ## delete query helper
  @staticmethod
  def __del_dict(d, k):
    try:
      del d[k]
    except KeyError:
      pass

  ## update path params
  def param(self, param, value=None):
    if value is None:
      for k in param: