#!/usr/bin/python
# -*- coding: utf-8 -*-
#
#    Copyright (C) 2016 Zomboided
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#    Shared code to return info about an IP connection.

import urllib2
import xbmcaddon
import xbmcgui
import json
from utility import ifHTTPTrace, ifJSONTrace, debugTrace, infoTrace, errorTrace, ifDebug, newPrint, getID


ip_sources = ["Auto select", "ipinfo.io", "IP-API", "ipstack"]
ip_urls = ["", "http://ipinfo.io/json", "http://ip-api.com/json", "http://api.ipstack.com/check?access_key=bb652555791d46c20bd3672e16d03ecb"] 
LIST_DEFAULT = "0,0,0"

MAX_ERROR = 64


def getIPInfoFrom(source):
    # Generate request to find out where this IP is based
    # Successful return is ip, country, region, city, isp 
    # Otherwise error strings are returned for the caller to parse
    try:
        # Determine the URL, make the call and read the response
        url = getIPSourceURL(source)
        if url == "": return "error", "error", "error", "unknown source", ""
        if ifHTTPTrace(): debugTrace("Using " + url)
        req = urllib2.Request(url)
        req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0")
        response = urllib2.urlopen(req, timeout = 10)
        json_data = json.load(response)   
        response.close()
        if ifJSONTrace(): infoTrace("ipinfo.py", "JSON received is \n" + json.dumps(json_data, indent=4))
    except urllib2.HTTPError as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", "API call was " + url)
        errorTrace("ipinfo.py", "Response was " + str(e.code) + " " + e.reason)
        errorTrace("ipinfo.py", e.read())
        recordError(source)
        return "error", "unknown location", "unknown location", "call failed", "unknown ISP"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", "API call was " + url)
        errorTrace("ipinfo.py", "Response was " + str(type(e)) + " " + str(e))
        recordError(source)
        return "no response", "error", "error", "connection failed", "unknown ISP"
        
    try:
        if source == "ipinfo.io": ip, country, region, city, isp = getipinfo(json_data)
        if source == "IP-API": ip, country, region, city, isp = getIPAPI(json_data)
        if source == "ipstack": ip, country, region, city, isp = getipstack(json_data)
        if not ip == None:
            recordWorking(source)
            return ip, country, region, city, isp
        else:
            errorTrace("ipinfo.py", "Couldn't get data from " + "source")
            recordError(source)
            return "no info", "unknown location", "unknown location", "no matches", "unknown ISP"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse response from IP provider " + source)
        errorTrace("ipinfo.py", str(e))
        recordError(source)
        return "error", "error", "error", "parse failed", "unknown ISP"

        
def getipinfo(json_data):
    try:
        ip = json_data["ip"]
        country = json_data["country"]
        region = json_data["region"]
        city = json_data["city"]
        isp = json_data["org"]        
        return ip, country, region, city, isp
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse JSON data " + str(json_data))
        errorTrace("ipinfo.py", str(e))
        return None, None, None, None, None               
        

def getIPAPI(json_data):
    try:
        ip = json_data["query"]
        country = json_data["country"]
        region = json_data["regionName"]
        city = json_data["city"]
        isp = json_data["isp"]        
        return ip, country, region, city, isp
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse JSON data " + str(json_data))
        errorTrace("ipinfo.py", str(e))
        return None, None, None, None, None               
        
        
def getipstack(json_data):
    try:
        ip = json_data["ip"]
        country = json_data["country_name"]
        region = json_data["region_name"]
        city = json_data["city"]       
        return ip, country, region, city, "Unknown"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse JSON data " + str(json_data))
        errorTrace("ipinfo.py", str(e))
        return None, None, None, None, None 


def isAutoSelect(source):
    if source == ip_sources[0]: return True
    return False

        
def getIPSources():
    return ip_sources


def getIPSourceURL(source):
    i = ip_sources.index(source)
    return ip_urls[i]


def getNextSource(current_source):
    next = ip_sources.index(current_source)
    next = next + 1
    if next == len(ip_sources): next = 1
    # Record that we're using another source
    source = xbmcgui.Window(10000).getProperty("VPN_Manager_Last_IP_Service")
    return ip_sources[next]
    

def recordError(source):
    # Double the error value each time to 64
    i = ip_sources.index(source)
    error = getErrorValue(i)
    if error == 0 : error = 1
    else : error = error * 2
    if error > MAX_ERROR : error = MAX_ERROR
    setErrorValue(i, error)

    
def recordWorking(source):
    i = ip_sources.index(source)
    # If a service works (starts working again), set the error value to 0
    setErrorValue(i, 0)
    working = getWorkingValue(i)
    working = working + 1
    if working > MAX_ERROR : working = 0
    setWorkingValue(i, working)
    xbmcgui.Window(10000).setProperty("VPN_Manager_Last_IP_Service", source)


    
def getAutoSource():
    # If the VPN has changed, then reset all the numbers        
    addon = xbmcaddon.Addon(getID())
    last_vpn = addon.getSetting("ip_service_last_vpn")
    current_vpn = addon.getSetting("vpn_provider_validated")
    if (not last_vpn == current_vpn):
        addon.setSetting("ip_service_last_vpn", current_vpn)
        resetIPServices()

    # Get the last source we tried to use from the home window or use the first if this is first time through
    source = xbmcgui.Window(10000).getProperty("VPN_Manager_Last_IP_Service")
    if source == "":
        # Record that we're using the first one
        xbmcgui.Window(10000).setProperty("VPN_Manager_Last_IP_Service", ip_sources[1])
        return ip_sources[1]
    else:
    	index = ip_sources.index(source)
        if index > 1:
            if getWorkingValue(index) >= getErrorValue(index - 1):
                setWorkingValue(index, 0)
                index = index - 1
        return ip_sources[index]


def resetIPServices():
    addon = xbmcaddon.Addon(getID())
    addon.setSetting("ip_service_errors", LIST_DEFAULT)
    addon.setSetting("ip_service_values", LIST_DEFAULT)
    xbmcgui.Window(10000).setProperty("VPN_Manager_Last_IP_Service", ip_sources[1])


def getIndex(source):
    return ip_sources.index(source)
    
    
def getErrorValue(index):
    index -= 1
    errors = xbmcaddon.Addon(getID()).getSetting("ip_service_errors")
    if not errors == "":
        list = errors.split(",")
        if not index > len(list):
            return int(list[index])
    return 0
    
    
def setErrorValue(index, value):
    index -= 1
    errors = xbmcaddon.Addon(getID()).getSetting("ip_service_errors")    
    if errors == "": errors = LIST_DEFAULT
    list = errors.split(",")
    i = 0
    output = ""
    while i < (len(list)):
        if i > 0: output = output + ","
        if i == index: output = output + str(value)
        else: output = output + str(list[i])
        i += 1
    xbmcaddon.Addon(getID()).setSetting("ip_service_errors", output)
    
    
def getWorkingValue(index):
    index -= 1
    values = xbmcaddon.Addon(getID()).getSetting("ip_service_values")
    if not values == "":
        list = values.split(",")
        if not index > len(list):
            return int(list[index])
    return 0
    
    
def setWorkingValue(index, value):
    index -= 1
    values = xbmcaddon.Addon(getID()).getSetting("ip_service_values")    
    if values == "": values = LIST_DEFAULT
    list = values.split(",")
    i = 0
    output = ""
    while i < (len(list)):
        if i > 0: output = output + ","
        if i == index: output = output + str(value)
        else: output = output + str(list[i])
        i += 1
    xbmcaddon.Addon(getID()).setSetting("ip_service_values", output)