# Permission to use this file is granted in hearts/license.txt.

from decimal import Decimal

from .scale import Scale


class Ordinal(Scale):
  '''
  A scale that maps individual values (e.g. strings) to a range.
  '''

  def __init__(self, domain):
    self._domain = domain


  def contains(self, v):
    '''
    Return :code:`True` if a given value is contained within this scale's
    displayed domain.
    '''
    return v in self._domain


  def project(self, value, range_min, range_max):
    '''
    Project a value in this scale's domain to a target range.
    '''
    range_min = Decimal(range_min)
    range_max = Decimal(range_max)

    segments = len(self._domain)
    segment_size = (range_max - range_min) / segments

    try:
      pos = range_min + (self._domain.index(value) * segment_size) + (segment_size / 2)
    except ValueError:
      raise ValueError('Value "%s" is not present in Ordinal scale domain' % value)

    return pos


  def project_interval(self, value, range_min, range_max):
    '''
    Project a value in this scale's domain to an interval in the target
    range. This is used for places :class:`.Bars`.
    '''
    range_min = Decimal(range_min)
    range_max = Decimal(range_max)

    segments = len(self._domain)
    segment_size = (range_max - range_min) / segments
    gap = segment_size / Decimal(20)

    try:
      a = range_min + (self._domain.index(value) * segment_size) + gap
      b = range_min + ((self._domain.index(value) + 1) * segment_size) - gap
    except ValueError:
      raise ValueError('Value "%s" is not present in Ordinal scale domain' % value)

    return (a, b)


  def ticks(self):
    '''
    Generate a series of ticks for this scale.
    '''
    return self._domain
