// This class assumes you are using Dreamlo for leaderboards
//
// If you aren't then you will not get much use out of this class.

using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;

public class TM_LeaderboardEntry
{
    public string strName;
    public int iVal1;
    public int iVal2;
    public string strVal3;

    //Position on Leaderboard
    public int iRank;

    //Last updated
    public System.DateTime time;

    public void FillData(string strData)
    {
        if (string.IsNullOrEmpty(strData))
            return;

        //Debug.Log("Calling FIllData on " + strData);

        string[] splitData = null;

        if( strData.Contains("|"))
        {
            splitData = strData.Split('|');
        }
        else
        {
            strData = strData.Replace("\"","");
            splitData = strData.Split(',');
        }

        try
        {
            strName = splitData[0];
            iVal1 = int.Parse(splitData[1]);
            if (!string.IsNullOrEmpty(splitData[2]))
                iVal2 = int.Parse(splitData[2]);
            if (!string.IsNullOrEmpty(splitData[3]))
                strVal3 = splitData[3];
            time = System.DateTime.Parse(splitData[4]);
            if (splitData.Length > 5)
                iRank = int.Parse(splitData[5]);
        }
        catch
        {

        }
    }
}

public class TM_LeaderboardManager : MonoBehaviour
{
    private static string strDreamloURLBase;
    public static void SetDreamloURLBase(string strBase) { strDreamloURLBase = strBase; }

    private static bool _bWaitingForLeaderboards;
    public static bool bWaitingForLeaderboards
    {
        get
        {
            return _bWaitingForLeaderboards;
        }
    }

    public static List<TM_LeaderboardEntry> top100LeaderboardEntries;
    public static List<TM_LeaderboardEntry> nearPlayerLeaderboardEntries;


    //Most recent result returned from the Dreamlo boards
    private int iMostRecentLeaderboardRank = -1;
    private string strMostRecentURLReadyPlayerName;

    //how many entries should we show for the leaderboards in general
    //and for the player-centric leaderboard entries
    private int iRangeAbovePlayerRank = 5;
    private int iNumEntriesToReceiveForPlayerCentricQuery = 15;

    private static List<Action> onLeaderboardDirtyFunctions;

    static void Awake()
    {
        top100LeaderboardEntries = new List<TM_LeaderboardEntry>();
        nearPlayerLeaderboardEntries = new List<TM_LeaderboardEntry>();
        onLeaderboardDirtyFunctions = new List<Action>();
    }

    #region Singleton Crap
    private static TM_LeaderboardManager _instance;
    private static TM_LeaderboardManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<TM_LeaderboardManager>();

                if (_instance != null)
                {
                    return _instance;
                }

                GameObject go = new GameObject("TM_LeaderboardManager");
                _instance = go.AddComponent<TM_LeaderboardManager>();
            }

            return _instance;
        }

    }
    #endregion


    #region Callbacks
    public static void AddOnLeaderboardDirtyFunction(Action func)
    {
        AddActionToListInternal(ref onLeaderboardDirtyFunctions, func);
    }

    private static void AddActionToListInternal(ref List<Action> myList, Action func)
    {
        if (myList == null)
            myList = new List<Action>();

        if (!myList.Contains(func))
            myList.Add(func);
    }
    #endregion

    int GetRankFromSingleEntry(string strData)
    {
        TM_LeaderboardEntry le = new TM_LeaderboardEntry();
        le.FillData(strData);
        return le.iRank;
    }

    public static void SendUpLeaderboardData( string strName, int val1, int val2 = 0, string strVal3 = null )
    {
        TM_LeaderboardEntry le = new TM_LeaderboardEntry();
        le.strName = strName;
        le.iVal1 = val1;
        le.iVal2 = val2;
        le.strVal3 = strVal3;

        SendUpLeaderboardData(le);
    }

    public static void SendUpLeaderboardData(TM_LeaderboardEntry le)
    {
        Instance.SendLeaderboardEntryInternal(le);
    }

    private void SendLeaderboardEntryInternal(TM_LeaderboardEntry le)
    {
        StartCoroutine(SendLeaderboardEntry(le));
    }

    private IEnumerator SendLeaderboardEntry(TM_LeaderboardEntry le)
    {
        //Debug.Log("SendNewHighScoreToWeb " + le.strName + " " + le.iScore);

        _bWaitingForLeaderboards = true;

        strMostRecentURLReadyPlayerName = le.strName;
        string fixedVal3 = le.strVal3;

        if (!string.IsNullOrEmpty(strMostRecentURLReadyPlayerName))
            strMostRecentURLReadyPlayerName = strMostRecentURLReadyPlayerName.Replace(" ", "%20");

        StringBuilder urlBuilder = new StringBuilder("http://dreamlo.com/lb/" + strDreamloURLBase + "/add-pipe/" + strMostRecentURLReadyPlayerName + "/" + le.iVal1.ToString() + "/" + le.iVal2.ToString());

        if (!string.IsNullOrEmpty(fixedVal3))
        {
            fixedVal3 = fixedVal3.Replace(" ", "%20");
            urlBuilder.Append("/" + fixedVal3);
        }

        WWW www = new WWW(urlBuilder.ToString());
        
        //Debug.Log("Yielding return "); // + le.strName + " " + le.iScore);
        yield return www;

        iMostRecentLeaderboardRank = GetRankFromSingleEntry(www.text);

        _bWaitingForLeaderboards = false;
        StartCoroutine(GetLeaderboardsFromWebCoroutine());
    }

    public static void GetLeaderboardsFromWeb()
    {
       Instance.GetLeaderboardsFromWebInternal();
    }

    private void GetLeaderboardsFromWebInternal()
    {
        StartCoroutine(GetLeaderboardsFromWebCoroutine());
    }

    //This will get back both the top 100 leaderboard entries, and the ranged leaderboard entries
    public IEnumerator GetLeaderboardsFromWebCoroutine()
    {
        //Get top 100 leaderboards
        _bWaitingForLeaderboards = true;
        string url = "http://dreamlo.com/lb/" + strDreamloURLBase + "/pipe/";
        WWW www = new WWW(url);
        yield return www;

        string strResults = www.text;
        Debug.Log("The internet says: " + strResults);

        FillLeaderboardDataFromString(strResults, ref top100LeaderboardEntries, 1);
        
        Debug.Log("My list is now " + top100LeaderboardEntries.Count + " big.");

        //If the player is on the leaderboards, find them and get the rank.
        if (iMostRecentLeaderboardRank == -1 && !string.IsNullOrEmpty(strMostRecentURLReadyPlayerName))
        {
            url = "http://dreamlo.com/lb/" + strDreamloURLBase + "/pipe-get/" + strMostRecentURLReadyPlayerName;
            www = new WWW(url);
            yield return www;
            if (www.text != null)
            {
                iMostRecentLeaderboardRank = GetRankFromSingleEntry(www.text);
                Debug.Log("and " + strMostRecentURLReadyPlayerName + " is ranked " + iMostRecentLeaderboardRank);
            }
            else
            {
                Debug.Log("...but " + strMostRecentURLReadyPlayerName + " isn't on the high score list!?");
            }

        }
        else
        {
            Debug.Log("But there was no high score name...");
        }

        int iStartVal = iMostRecentLeaderboardRank - iRangeAbovePlayerRank;
        if (iStartVal < 0)
            iStartVal = 0;

        url = "http://dreamlo.com/lb/" + strDreamloURLBase + "/pipe/" + iStartVal + "/" + iNumEntriesToReceiveForPlayerCentricQuery;
        www = new WWW(url);
        yield return www;

        strResults = www.text;
        Debug.Log("The internet says: " + strResults);

        FillLeaderboardDataFromString(strResults, ref nearPlayerLeaderboardEntries, iStartVal + 1);
        Debug.Log("My list is now " + nearPlayerLeaderboardEntries.Count + " big.");
        _bWaitingForLeaderboards = false;

        if (onLeaderboardDirtyFunctions != null)
        {
            for (int t = 0; t < onLeaderboardDirtyFunctions.Count; t++)
            {
                Action a = onLeaderboardDirtyFunctions[t];
                a();
            }
        }
    }

    private void FillLeaderboardDataFromString(string strData, ref List<TM_LeaderboardEntry> entryList, int iFirstRank)
    {
        string[] strAllEntries = strData.Split('\n');
        //Debug.Log("There are " + strAllEntries.Length + " entries.");

        //-1 because last data from server is null
        int iNum = strAllEntries.Length - 1;
        entryList = new List<TM_LeaderboardEntry>();
        for (int t = 0; t < iNum; t++)
        {
            TM_LeaderboardEntry le = new TM_LeaderboardEntry();
            le.FillData(strAllEntries[t]);
            le.iRank = t + iFirstRank;

            //Debug.Log("Rank " + le.iRank + ": " + le.iScore.ToString() + " " + le.strName);
            entryList.Add(le);
        }
    }
}