using UnityEngine;

using UnityEngine.UI;
using System.Collections;

public interface IScrollContent {
    int CurrentRecord { get; set; }
    int TotalRecords { get; }
    void FillContent (GameObject resource, int index);
}

public class ScrollList : MonoBehaviour {

    public bool ReuseContent = false;
    public GameObject ContentSource = null;
    public GameObject ContentTemplate = null;

    IScrollContent scrollContent = null;

    GameObject[] contentResources = null;
    ScrollRect scrollRect = null;
    float resourceAnchor = 0f;
    Vector2 resourcePadding = Vector2.zero;

    int First = 0;
    int Last { get { return First + contentResources.Length  1; } }
    int PadCells = 3;

    void Initialize() {
        scrollContent = ContentSource.GetComponent(typeof(IScrollContent)) as IScrollContent;
        scrollRect = GetComponent<ScrollRect>();

        int contentCount = TileCount();
        ResizeContent();

        contentResources = new GameObject[contentCount];
        for (int i = 1; i < contentResources.Length; i++)
            contentResources[i] = Instantiate(ContentTemplate) as GameObject;

        if (contentResources.Length > 0) 
            contentResources[0] = ContentTemplate;
    }

    int TileCount () {
        if (!ReuseContent) return scrollContent.TotalRecords;

        bool horizontal = scrollRect.horizontal;

        RectTransform scrollTransform = scrollRect.transform as RectTransform;
        RectTransform resourceRect = ContentTemplate.transform as RectTransform;

        int fit = horizontal
            ? (int)(scrollTransform.rect.width / resourceRect.rect.width)
                : (int)(scrollTransform.rect.height / resourceRect.rect.height);

        fit += PadCells * 2;

        return fit;
    }

    void ResizeContent () {
        RectTransform contentRect = scrollRect.content.transform as RectTransform;
        RectTransform resourceRect = ContentTemplate.transform as RectTransform;

        bool horizontal = scrollRect.horizontal;
        int totalRecords = scrollContent.TotalRecords;

        float resourceSize = horizontal
            ? resourceRect.rect.width
            : resourceRect.rect.height;

        float contentSize = resourceSize * totalRecords;

        contentRect.offsetMin = new Vector2(0f, 0f);
        contentRect.offsetMax = horizontal
            ? new Vector2(contentSize  contentRect.rect.width, contentRect.offsetMax.y)
            : new Vector2(contentRect.offsetMax.x, contentSize  contentRect.rect.height);

        resourceAnchor = resourceSize / contentSize;
        resourcePadding = resourceRect.offsetMin;
    }

    void FillContent(int resource, int index) {
        if (index >= 0 && index < scrollContent.TotalRecords) {
            contentResources[resource].SetActive(true);
            scrollContent.FillContent(contentResources[resource], index);
        } else {
            contentResources[resource].SetActive(false);
        }
    }

    public void RefreshContent() {
        for (int i = 0; i < contentResources.Length; i++) {
            FillContent (i, First + i);
        }
    }

    public void ScrollTo(int index) {
        if (contentResources == null)
            Initialize();

        bool horizontal = scrollRect.horizontal;

        // center the index (if possible)
        First = index  contentResources.Length / 2;
        int last = First + contentResources.Length;

        if (last > scrollContent.TotalRecords)
            First -= (last  scrollContent.TotalRecords);
        if (First < 0) 
            First = 0;

        Vector2 indexPos = Vector2.zero;

        for (int i = 0; i < contentResources.Length; i++) {
            int listPos = First + i;

            AssignResource(i, listPos);

            if (index == listPos) {
                RectTransform resourceRect = contentResources[i].transform as RectTransform;
                indexPos = resourceRect.localPosition;
            }
        }

        RectTransform contentRect = scrollRect.content.transform as RectTransform;
        float offset = (horizontal ? indexPos.: indexPos.y);

        Vector2 pos = new Vector2(horizontal ? offset : 0f, horizontal ? 0f : offset);
        contentRect.localPosition = pos;
    }

    void AssignResource (int resource, int index) {
        RectTransform resourceRect = contentResources[resource].transform as RectTransform;
        
        resourceRect.SetParent(scrollRect.content.transform);
        
        if (scrollRect.horizontal) {
            resourceRect.anchorMin = new Vector2(resourceAnchor * index, 0f);
            resourceRect.anchorMax = new Vector2(resourceAnchor * (index + 1), 1f);
        } else { // vertical
            float min = 1f  (resourceAnchor * (index+1));
            float max = 1f  (resourceAnchor * (index));
            
            resourceRect.anchorMin = new Vector2(0f, min);
            resourceRect.anchorMax = new Vector2(1f, max);
        }
        
        resourceRect.offsetMin = resourcePadding;
        resourceRect.offsetMax = resourcePadding;

        FillContent(resource, index);
    }

    public void DecrementResource () {
        if (First <= 0)
            return;

        Debug.Log(Decrement: First:  + First +  Last:  + Last +  Count:  + contentResources.Length);

        int c = contentResources.Length  1;
        GameObject first = contentResources[c];
        for (int i = c ; i > 0; i)
        {
            contentResources[i] = contentResources[i1];
        }
        contentResources[0] = first;

        First–;
        AssignResource(0, First);
    }

    public void IncrementResource () {
        if (Last >= (scrollContent.TotalRecords1)) 
            return;

        GameObject last = contentResources[0];
        int c = contentResources.Length  1;
        for (int i = 0; i < c; i++)
        {
            contentResources[i] = contentResources[i+1];
        }
        contentResources[c] = last;

        First++;
        AssignResource(c, Last);
    }

    public void OnValueChanged () {
        if (scrollRect == null || scrollRect.content == null)
            return;

        RectTransform contentRect = scrollRect.content.transform as RectTransform;
        RectTransform resourceRect = ContentTemplate.transform as RectTransform;

        // correct for ends
        RectTransform parentRect = scrollRect.transform as RectTransform;
        Vector2 position = contentRect.position;

        position.+= contentRect.rect.height;
        position.-= (parentRect.rect.height * 1.5f);
        position.+= (resourceRect.rect.height * 2f);

        Vector2 size = new Vector2(contentRect.rect.width, contentRect.rect.height);
        float percent = position./ size.y;
        int calcFirst = (int)(percent * (float)scrollContent.TotalRecords);
        calcFirst -= PadCells;
        int deltaFirst = calcFirst  First;

        while (deltaFirst < 1) {
            DecrementResource();
            deltaFirst++;
        }
        while (deltaFirst > 1) {
            IncrementResource();
            deltaFirst–;
        }
    }
}