import types

utest = False
if __name__ == "__main__":
    utest = True
    import pprint

#-------------------------------------------------------------------------------
def ver_cmp(v1, v2):
  minlen = min(len(v1), len(v2))
  return cmp(v1[0:minlen], v2[0:minlen])

#===============================================================================
#
#===============================================================================
# Class that represents option definition. Must be r/o. Init from opts.py
# dict for an option. All the values
class OptionDef(object):
    name        = None
    caption     = None
    description = None
    values      = None
    versions    = None

    #---------------------------------------------------------------------------
    def __init__(self, option_dict):
        self.name        = option_dict.get("name")
        self.caption     = option_dict.get("caption")
        self.description = option_dict.get("description")
        self.versions    = option_dict.get("versions")
        self.values      = option_dict.get("values")

        # Fix empty values

        if type(self.versions) is not list:
            self.versions = ((), (), ())
            print "Option '%s' has no versions" % self.name

    #---------------------------------------------------------------------------
    def __str__(self):
        r = ["Option"]
        for i in dir(self):
            if i[0] != '_':
                attr = getattr(self, i)
                if type(attr) is not types.MethodType:
                    r.append("%s = %s"%(i, str(attr)))
        return "\n  ".join(r)

    #---------------------------------------------------------------------------
    def is_valid(self):
        return (type(self.values) is list) and (len(self.values) > 0)

    #---------------------------------------------------------------------------
    # The method is used to filter options which are relevant to a server version
    def is_valid_for_server_version(self, version):
        (inver, vlist, outver) = self.versions

        ret = False

        matched_version = None
        # Check if we have x.y version in list which allows version
        for v in vlist:
          if ver_cmp(version, v) == 0:
            matched_version = v
            ret = True
            break

        # Check that version is within introduced and removed
        # If not drop ret to False
        if matched_version:
          if inver is not None:
            for iv in inver:
              if matched_version[:2] == iv[:2]:
                if ver_cmp(version, iv) < 0:
                  ret = False
                break

          if outver is not None:
            out_ver = None
            for ov in outver:
              if matched_version[:2] == ov[:2]:
                if ver_cmp(version, ov) > 0:
                  ret = False
                break

        return ret


    #---------------------------------------------------------------------------
    def get_corresponding_value(self, version, platform, bits):
        value = None
        if type(self.values) is list and len(self.values) > 0:
            # Walk all values and pick best match
            for cur_value in self.values:
                inversion  = cur_value.get('inversion')
                outversion = cur_value.get('outversion')

                if inversion is None:
                    inversion = (0,0,0)

                if outversion is None:
                    outversion = (99,0,0)

                if version >= inversion and version <= outversion:
                    platform_match = False
                    if 'platform' in cur_value:
                        pl = cur_value['platform']
                        if pl == platform or pl == 'all' or platform == "all" or platform is None:
                            platform_match = True
                    else:
                        platform_match = True

                    if platform_match:
                        value = cur_value
                        break

        return value




#===============================================================================
#
#===============================================================================
class Option(object):
    odef      = None
    value     = None
    value_def = None
    otype     = None

    #---------------------------------------------------------------------------
    def __init__(self, option_def, version, platform, bits):
        self.odef = option_def
        self.value_def = option_def.get_corresponding_value(version, platform, bits)
        self.otype = self.value_def['type']
        self.value = self.default

    #---------------------------------------------------------------------------
    @property
    def option_type(self):
        return self.otype

    #---------------------------------------------------------------------------
    @property
    def name(self):
        return self.odef.name

    #---------------------------------------------------------------------------
    @property
    def default(self):
        return self.value_def.get('default', "")

    #---------------------------------------------------------------------------
    def get_value(self):
        return self.value

    #---------------------------------------------------------------------------
    def set_value(self, v):
        # TODO: run verification?
        self.value = v




#===============================================================================
# Tests
#===============================================================================
if utest:
    import raw_opts
    import sys

    plats = ['windows', 'linux', 'other', 'all', None]

    cnt = 0
    platform = None
    for optdict in raw_opts.ropts:
      odef = OptionDef(optdict)
      if odef.is_valid():
        for major in [5]:
          for minor in [1]:
            for sub in range(30,31):
              try:
                version = (major,minor,sub)
                if odef.is_valid_for_server_version(version):
                  o = Option(odef, version, platform, None)
                  print "%2i %-36s %-10s  %-10s  %-10s %s" % (cnt, o.name, o.option_type, o.value, o.default, str(o.value_def))
              except (AttributeError, TypeError), e:
                print "Exception ", odef.name, platform, version, str(e)
              cnt += 1

    