package com.atlassian.confluence.extra.tasklist.model;

import com.atlassian.confluence.core.ContentEntityObject;
import com.atlassian.confluence.core.ContentPropertyManager;
import com.atlassian.confluence.renderer.PageContext;
import com.atlassian.confluence.util.GeneralUtil;
import com.atlassian.renderer.v2.SubRenderer;
import com.atlassian.renderer.v2.RenderMode;
import com.opensymphony.util.TextUtils;

import java.util.*;

import org.apache.commons.collections.SequencedHashMap;

/**
 * Defines a very simple task list model.
 * <p>
 * Tasks are text strings, one per line.
 */
public class TaskList
{
    private final String name;
    private final ContentEntityObject content;
    private final ContentPropertyManager contentPropertyManager;
    Map tasks;
    private SubRenderer subRenderer;
    private PageContext context;

    public TaskList(String name, ContentEntityObject content, String body, ContentPropertyManager contentPropertyManager, SubRenderer subRenderer, PageContext pageContext)
    {
        this.name = name;
        this.content = content;
        this.contentPropertyManager = contentPropertyManager;
        this.subRenderer = subRenderer;
        this.context = pageContext;
        createTasks(body);
    }

    private void createTasks(String body)
    {
        tasks = new SequencedHashMap();

        for (StringTokenizer stringTokenizer = new StringTokenizer(body, "\r\n"); stringTokenizer.hasMoreTokens();)
        {
            String rawLine = TextUtils.noNull(stringTokenizer.nextToken()).trim(); // critical to trim the item first, otherwise "fruit" and "fruit   " will be added as separate entries. CONF-3633
            String renderedLine = subRenderer.render(rawLine, context, RenderMode.INLINE);
            final Task task = new Task(rawLine, renderedLine);

            if (content != null)
            {
                String entityKey = computeTaskItemId(task.getName());
                String completer = contentPropertyManager.getStringProperty(content, entityKey);

                if (TextUtils.stringSet(completer))
                {
                    task.setCompleter(completer);
                }
            }

            tasks.put(task.getName(), task);
        }
    }

    /**
     * hash the name of the task list and the task item to keep the entity key under 200 characters (new limit of the OS_PROPERTYENTRY.ENTITY_KEY column)
     * @param taskItemName
     * @return
     */
    public String computeTaskItemId(String taskItemName)
    {
        return "tasklist." + TextUtils.noNull(name).hashCode() + "." + TextUtils.noNull(taskItemName).hashCode();
    }

    public String getName()
    {
        return name;
    }

    public List getTasks()
    {
        return new ArrayList(tasks.values());
    }

    /**
     * Mark a given task compelte, with optionally the user that completed it.
     */
    public void completeTask(String taskname, String username)
    {
        Task task = (Task) tasks.get(taskname);

        if (task != null)
        {
            if (!TextUtils.stringSet(username))
                username = "Unknown";

            String entityKey = computeTaskItemId(taskname);
            contentPropertyManager.setStringProperty(content, entityKey, username);
            task.setCompleter(username);
        }
    }

    /**
     * Mark a task as uncomplete.
     */
    public void uncompleteTask(String taskname)
    {
        Task task = (Task) tasks.get(taskname);

        if (task != null)
        {
            clearTask(task);
        }
    }

    public void uncompleteAllTasks()
    {
        List tasks = getTasks();
        for (Iterator iterator = tasks.iterator(); iterator.hasNext();)
        {
            Task task = (Task) iterator.next();
            if(task != null)
            {
                clearTask(task);
            }
        }
    }

    public int getPercentComplete()
    {
        int complete = 0;

        for (Iterator iterator = getTasks().iterator(); iterator.hasNext();)
        {
            Task task = (Task) iterator.next();
            if (task.isCompleted())
            {
                complete++;
            }
        }

        return (int)(100f * ((float)complete / (float)tasks.size()));
    }

    private void clearTask(Task task)
    {
        String entityKey = computeTaskItemId(task.getName());
        contentPropertyManager.setStringProperty(content, entityKey, null);
        task.setCompleter(null);
    }
}