# -*- coding: utf-8 -*-


class CountryUtils(object):
    significant_country_match = 6
    significant_code_match = 3

    country_code_map_by_country = dict()
    country_code_map_by_country["Afghanistan"] = "AF"
    country_code_map_by_country["Aland Islands"] = "AX"
    country_code_map_by_country["Albania"] = "AL"
    country_code_map_by_country["Algeria"] = "DZ"
    country_code_map_by_country["American Samoa"] = "AS"
    country_code_map_by_country["Andorra"] = "AD"
    country_code_map_by_country["Angola"] = "AO"
    country_code_map_by_country["Anguilla"] = "AI"
    country_code_map_by_country["Antarctica"] = "AQ"
    country_code_map_by_country["Antigua and Barbuda"] = "AG"
    country_code_map_by_country["Argentina"] = "AR"
    country_code_map_by_country["Armenia"] = "AM"
    country_code_map_by_country["Aruba"] = "AW"
    country_code_map_by_country["Australia"] = "AU"
    country_code_map_by_country["Austria"] = "AT"
    country_code_map_by_country["Azerbaijan"] = "AZ"
    country_code_map_by_country["Bahamas"] = "BS"
    country_code_map_by_country["Bahrain"] = "BH"
    country_code_map_by_country["Bangladesh"] = "BD"
    country_code_map_by_country["Barbados"] = "BB"
    country_code_map_by_country["Belarus"] = "BY"
    country_code_map_by_country["Belgium"] = "BE"
    country_code_map_by_country["Belize"] = "BZ"
    country_code_map_by_country["Benin"] = "BJ"
    country_code_map_by_country["Bermuda"] = "BM"
    country_code_map_by_country["Bhutan"] = "BT"
    country_code_map_by_country["Bolivia (Plurinational State of)"] = "BO"
    country_code_map_by_country["Bonaire, Sint Eustatius and Saba"] = "BQ"
    country_code_map_by_country["Bosnia and Herzegovina"] = "BA"
    country_code_map_by_country["Botswana"] = "BW"
    country_code_map_by_country["Bouvet Island"] = "BV"
    country_code_map_by_country["Brazil"] = "BR"
    country_code_map_by_country["British Indian Ocean Territory"] = "IO"
    country_code_map_by_country["Brunei Darussalam"] = "BN"
    country_code_map_by_country["Bulgaria"] = "BG"
    country_code_map_by_country["Burkina Faso"] = "BF"
    country_code_map_by_country["Burundi"] = "BI"
    country_code_map_by_country["Cambodia"] = "KH"
    country_code_map_by_country["Cameroon"] = "CM"
    country_code_map_by_country["Canada"] = "CA"
    country_code_map_by_country["Cabo Verde"] = "CV"
    country_code_map_by_country["Cayman Islands"] = "KY"
    country_code_map_by_country["Central African Republic"] = "CF"
    country_code_map_by_country["Chad"] = "TD"
    country_code_map_by_country["Chile"] = "CL"
    country_code_map_by_country["China"] = "CN"
    country_code_map_by_country["Christmas Island"] = "CX"
    country_code_map_by_country["Cocos (Keeling) Islands"] = "CC"
    country_code_map_by_country["Colombia"] = "CO"
    country_code_map_by_country["Comoros"] = "KM"
    country_code_map_by_country["Congo"] = "CG"
    country_code_map_by_country["Congo (Democratic Republic of the)"] = "CD"
    country_code_map_by_country["Cook Islands"] = "CK"
    country_code_map_by_country["Costa Rica"] = "CR"
    country_code_map_by_country["CÃ´te d'Ivoire"] = "CI"
    country_code_map_by_country["Croatia"] = "HR"
    country_code_map_by_country["Cuba"] = "CU"
    country_code_map_by_country["Curacao"] = "CW"
    country_code_map_by_country["Cyprus"] = "CY"
    country_code_map_by_country["Czech Republic"] = "CZ"
    country_code_map_by_country["Denmark"] = "DK"
    country_code_map_by_country["Djibouti"] = "DJ"
    country_code_map_by_country["Dominica"] = "DM"
    country_code_map_by_country["Dominican Republic"] = "DO"
    country_code_map_by_country["Ecuador"] = "EC"
    country_code_map_by_country["Egypt"] = "EG"
    country_code_map_by_country["El Salvador"] = "SV"
    country_code_map_by_country["Equatorial Guinea"] = "GQ"
    country_code_map_by_country["Eritrea"] = "ER"
    country_code_map_by_country["Estonia"] = "EE"
    country_code_map_by_country["Ethiopia"] = "ET"
    country_code_map_by_country["Falkland Islands (Malvinas)"] = "FK"
    country_code_map_by_country["Faroe Islands"] = "FO"
    country_code_map_by_country["Fiji"] = "FJ"
    country_code_map_by_country["Finland"] = "FI"
    country_code_map_by_country["France"] = "FR"
    country_code_map_by_country["French Guiana"] = "GF"
    country_code_map_by_country["French Polynesia"] = "PF"
    country_code_map_by_country["French Southern Territories"] = "TF"
    country_code_map_by_country["Gabon"] = "GA"
    country_code_map_by_country["Gambia"] = "GM"
    country_code_map_by_country["Georgia"] = "GE"
    country_code_map_by_country["Germany"] = "DE"
    country_code_map_by_country["Ghana"] = "GH"
    country_code_map_by_country["Gibraltar"] = "GI"
    country_code_map_by_country["Greece"] = "GR"
    country_code_map_by_country["Greenland"] = "GL"
    country_code_map_by_country["Grenada"] = "GD"
    country_code_map_by_country["Guadeloupe"] = "GP"
    country_code_map_by_country["Guam"] = "GU"
    country_code_map_by_country["Guatemala"] = "GT"
    country_code_map_by_country["Guernsey"] = "GG"
    country_code_map_by_country["Guinea"] = "GN"
    country_code_map_by_country["Guinea-Bissau"] = "GW"
    country_code_map_by_country["Guyana"] = "GY"
    country_code_map_by_country["Haiti"] = "HT"
    country_code_map_by_country["Heard Island and McDonald Islands"] = "HM"
    country_code_map_by_country["Holy See"] = "VA"
    country_code_map_by_country["Honduras"] = "HN"
    country_code_map_by_country["Hong Kong"] = "HK"
    country_code_map_by_country["Hungary"] = "HU"
    country_code_map_by_country["Iceland"] = "IS"
    country_code_map_by_country["India"] = "IN"
    country_code_map_by_country["Indonesia"] = "ID"
    country_code_map_by_country["Iran (Islamic Republic of)"] = "IR"
    country_code_map_by_country["Iraq"] = "IQ"
    country_code_map_by_country["Ireland"] = "IE"
    country_code_map_by_country["Isle of Man"] = "IM"
    country_code_map_by_country["Israel"] = "IL"
    country_code_map_by_country["Italy"] = "IT"
    country_code_map_by_country["Jamaica"] = "JM"
    country_code_map_by_country["Japan"] = "JP"
    country_code_map_by_country["Jersey"] = "JE"
    country_code_map_by_country["Jordan"] = "JO"
    country_code_map_by_country["Kazakhstan"] = "KZ"
    country_code_map_by_country["Kenya"] = "KE"
    country_code_map_by_country["Kiribati"] = "KI"
    country_code_map_by_country[
        "Korea (Democratic People's Republic of)"] = "KP"
    country_code_map_by_country["Korea (Republic of)"] = "KR"
    country_code_map_by_country["Kuwait"] = "KW"
    country_code_map_by_country["Kyrgyzstan"] = "KG"
    country_code_map_by_country["Lao People's Democratic Republic"] = "LA"
    country_code_map_by_country["Latvia"] = "LV"
    country_code_map_by_country["Lebanon"] = "LB"
    country_code_map_by_country["Lesotho"] = "LS"
    country_code_map_by_country["Liberia"] = "LR"
    country_code_map_by_country["Libya"] = "LY"
    country_code_map_by_country["Liechtenstein"] = "LI"
    country_code_map_by_country["Lithuania"] = "LT"
    country_code_map_by_country["Luxembourg"] = "LU"
    country_code_map_by_country["Macao"] = "MO"
    country_code_map_by_country[
        "Macedonia (the former Yugoslav Republic of)"] = "MK"
    country_code_map_by_country["Madagascar"] = "MG"
    country_code_map_by_country["Malawi"] = "MW"
    country_code_map_by_country["Malaysia"] = "MY"
    country_code_map_by_country["Maldives"] = "MV"
    country_code_map_by_country["Mali"] = "ML"
    country_code_map_by_country["Malta"] = "MT"
    country_code_map_by_country["Marshall Islands"] = "MH"
    country_code_map_by_country["Martinique"] = "MQ"
    country_code_map_by_country["Mauritania"] = "MR"
    country_code_map_by_country["Mauritius"] = "MU"
    country_code_map_by_country["Mayotte"] = "YT"
    country_code_map_by_country["Mexico"] = "MX"
    country_code_map_by_country["Micronesia (Federated States of)"] = "FM"
    country_code_map_by_country["Moldova (Republic of)"] = "MD"
    country_code_map_by_country["Monaco"] = "MC"
    country_code_map_by_country["Mongolia"] = "MN"
    country_code_map_by_country["Montenegro"] = "ME"
    country_code_map_by_country["Montserrat"] = "MS"
    country_code_map_by_country["Morocco"] = "MA"
    country_code_map_by_country["Mozambique"] = "MZ"
    country_code_map_by_country["Myanmar"] = "MM"
    country_code_map_by_country["Namibia"] = "NA"
    country_code_map_by_country["Nauru"] = "NR"
    country_code_map_by_country["Nepal"] = "NP"
    country_code_map_by_country["Netherlands"] = "NL"
    country_code_map_by_country["New Caledonia"] = "NC"
    country_code_map_by_country["New Zealand"] = "NZ"
    country_code_map_by_country["Nicaragua"] = "NI"
    country_code_map_by_country["Niger"] = "NE"
    country_code_map_by_country["Nigeria"] = "NG"
    country_code_map_by_country["Niue"] = "NU"
    country_code_map_by_country["Norfolk Island"] = "NF"
    country_code_map_by_country["Northern Mariana Islands"] = "MP"
    country_code_map_by_country["Norway"] = "NO"
    country_code_map_by_country["Oman"] = "OM"
    country_code_map_by_country["Pakistan"] = "PK"
    country_code_map_by_country["Palau"] = "PW"
    country_code_map_by_country["Palestine, State of"] = "PS"
    country_code_map_by_country["Panama"] = "PA"
    country_code_map_by_country["Papua New Guinea"] = "PG"
    country_code_map_by_country["Paraguay"] = "PY"
    country_code_map_by_country["Peru"] = "PE"
    country_code_map_by_country["Philippines"] = "PH"
    country_code_map_by_country["Pitcairn"] = "PN"
    country_code_map_by_country["Poland"] = "PL"
    country_code_map_by_country["Portugal"] = "PT"
    country_code_map_by_country["Puerto Rico"] = "PR"
    country_code_map_by_country["Qatar"] = "QA"
    country_code_map_by_country["RÃ©union"] = "RE"
    country_code_map_by_country["Romania"] = "RO"
    country_code_map_by_country["Russian Federation"] = "RU"
    country_code_map_by_country["Rwanda"] = "RW"
    country_code_map_by_country["Saint BarthÃ©lemy"] = "BL"
    country_code_map_by_country[
        "Saint Helena, Ascension and Tristan da Cunha"] = "SH"
    country_code_map_by_country["Saint Kitts and Nevis"] = "KN"
    country_code_map_by_country["Saint Lucia"] = "LC"
    country_code_map_by_country["Saint Martin (French part)"] = "MF"
    country_code_map_by_country["Saint Pierre and Miquelon"] = "PM"
    country_code_map_by_country["Saint Vincent and the Grenadines"] = "VC"
    country_code_map_by_country["Samoa"] = "WS"
    country_code_map_by_country["San Marino"] = "SM"
    country_code_map_by_country["Sao Tome and Principe"] = "ST"
    country_code_map_by_country["Saudi Arabia"] = "SA"
    country_code_map_by_country["Senegal"] = "SN"
    country_code_map_by_country["Serbia"] = "RS"
    country_code_map_by_country["Seychelles"] = "SC"
    country_code_map_by_country["Sierra Leone"] = "SL"
    country_code_map_by_country["Singapore"] = "SG"
    country_code_map_by_country["Sint Maarten (Dutch part)"] = "SX"
    country_code_map_by_country["Slovakia"] = "SK"
    country_code_map_by_country["Slovenia"] = "SI"
    country_code_map_by_country["Solomon Islands"] = "SB"
    country_code_map_by_country["Somalia"] = "SO"
    country_code_map_by_country["South Africa"] = "ZA"
    country_code_map_by_country[
        "South Georgia and the South Sandwich Islands"] = "GS"
    country_code_map_by_country["South Sudan"] = "SS"
    country_code_map_by_country["Spain"] = "ES"
    country_code_map_by_country["Sri Lanka"] = "LK"
    country_code_map_by_country["Sudan"] = "SD"
    country_code_map_by_country["Suriname"] = "SR"
    country_code_map_by_country["Svalbard and Jan Mayen"] = "SJ"
    country_code_map_by_country["Swaziland"] = "SZ"
    country_code_map_by_country["Sweden"] = "SE"
    country_code_map_by_country["Switzerland"] = "CH"
    country_code_map_by_country["Syrian Arab Republic"] = "SY"
    country_code_map_by_country["Taiwan, Province of China"] = "TW"
    country_code_map_by_country["Tajikistan"] = "TJ"
    country_code_map_by_country["Tanzania, United Republic of"] = "TZ"
    country_code_map_by_country["Thailand"] = "TH"
    country_code_map_by_country["Timor-Leste"] = "TL"
    country_code_map_by_country["Togo"] = "TG"
    country_code_map_by_country["Tokelau"] = "TK"
    country_code_map_by_country["Tonga"] = "TO"
    country_code_map_by_country["Trinidad and Tobago"] = "TT"
    country_code_map_by_country["Tunisia"] = "TN"
    country_code_map_by_country["Turkey"] = "TR"
    country_code_map_by_country["Turkmenistan"] = "TM"
    country_code_map_by_country["Turks and Caicos Islands"] = "TC"
    country_code_map_by_country["Tuvalu"] = "TV"
    country_code_map_by_country["Uganda"] = "UG"
    country_code_map_by_country["Ukraine"] = "UA"
    country_code_map_by_country["United Arab Emirates"] = "AE"
    country_code_map_by_country[
        "United Kingdom of Great Britain and Northern Ireland"] = "GB"
    country_code_map_by_country["United States of America"] = "US"
    country_code_map_by_country["United States Minor Outlying Islands"] = "UM"
    country_code_map_by_country["Uruguay"] = "UY"
    country_code_map_by_country["Uzbekistan"] = "UZ"
    country_code_map_by_country["Vanuatu"] = "VU"
    country_code_map_by_country["Venezuela (Bolivarian Republic of)"] = "VE"
    country_code_map_by_country["Viet Nam"] = "VN"
    country_code_map_by_country["Virgin Islands (British)"] = "VG"
    country_code_map_by_country["Virgin Islands (U.S.)"] = "VI"
    country_code_map_by_country["Wallis and Futuna"] = "WF"
    country_code_map_by_country["Western Sahara"] = "EH"
    country_code_map_by_country["Yemen"] = "YE"
    country_code_map_by_country["Zambia"] = "ZM"
    country_code_map_by_country["Zimbabwe"] = "ZW"

    country_map_by_country_code = dict()
    for country in country_code_map_by_country.keys():
        country_map_by_country_code[country_code_map_by_country[
            country]] = country

    @staticmethod
    def is_country(address, country_code):
        if address.country_code is not None:
            return address.country_code == country_code

        if address.country is not None:
            code = CountryUtils.get_country_code_by_country(address.country)

            if code is not None:
                return code == country_code

            return False

        return False

    @staticmethod
    def get_country_by_country_code(country_code):
        if country_code is None:
            return None

        if country_code in CountryUtils.country_map_by_country_code:
            return CountryUtils.country_map_by_country_code[country_code]

        if len(country_code) > 3:
            return None

        return CountryUtils.fuzzy_match(
            CountryUtils.country_map_by_country_code, country_code,
            CountryUtils.significant_code_match)

    @staticmethod
    def get_country_code_by_country(country):
        if country is None:
            return None

        if country in CountryUtils.country_code_map_by_country:
            return CountryUtils.country_code_map_by_country[country]

        match = CountryUtils.fuzzy_match(
            CountryUtils.country_code_map_by_country, country,
            CountryUtils.significant_country_match)

        if match is not None:
            return match

        if len(country) > 3:
            return None

        match = CountryUtils.fuzzy_match(
            CountryUtils.country_map_by_country_code, country,
            CountryUtils.significant_code_match)

        if match is not None:
            return match

        return None

    @staticmethod
    def fuzzy_match(dictionary, query, significant_match):
        rvalue = None
        matches = {}

        # loop
        high_score = -1
        for key in dictionary.keys():
            score = CountryUtils.fuzzy_score(key, query)

            if score > significant_match and score > high_score:
                matches = {}
                high_score = score
                rvalue = dictionary[key]
                matches[key] = rvalue

            elif score == high_score:
                matches[key] = dictionary[key]

        if len(matches) > 1:
            return None

        return rvalue

    @staticmethod
    def fuzzy_score(term, query):
        if term is None or query is None:
            return None

        term_lower_case = term.lower()
        query_lower_case = query.lower()

        score = 0
        term_index = 0
        previous_matching_character_index = -1

        for query_index in range(len(query_lower_case)):
            query_char = query_lower_case[query_index]

            term_character_match_found = False
            for term_index in range(len(term_lower_case)):
                if term_character_match_found:
                    pass

                term_char = term_lower_case[term_index]

                if query_char == term_char:
                    score = score + 1

                    if previous_matching_character_index + 1 == term_index:
                        score = score + 2

                    previous_matching_character_index = term_index
                    term_character_match_found = True

        return score


class Address(object):
    """
    Represents a billing or shipping address for the consumer.
    """

    address_type = None
    street_address_1 = None
    street_address_2 = None
    street_address_3 = None
    city = None
    province = None
    postal_code = None
    _country = None
    _country_code = None

    @property
    def state(self):
        return self.province

    @state.setter
    def state(self, value):
        self.province = value

    @property
    def country(self):
        return self._country

    @country.setter
    def country(self, value):
        self._country = value
        if self._country_code is None:
            self._country_code = CountryUtils.get_country_code_by_country(
                self._country)

    @property
    def country_code(self):
        return self._country_code

    @country_code.setter
    def country_code(self, value):
        self._country_code = value
        if self._country is None:
            self._country = CountryUtils.get_country_by_country_code(
                self._country_code)
