/* 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. 
 * 
 * This file is available and licensed under the following license:
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *   * Neither the name of Sun Microsystems nor the names of its contributors 
 *     may be used to endorse or promote products derived from this software 
 *     without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * DataHandler.fx
 *
 * Created on Apr 24, 2009, 5:54:56 PM
 */

package projectmanager;

import projectmanager.ProjectModel;
import projectmanager.TaskModel;

/**
 * DataHandler which takes care of the data manipulation and data initialization.
 * This class takes care of deleting the data, adding new data, updating the
 * existing data and synchronizing the corresponding view when the data changes.
 *
 * Takes care of task as well as project data and also populates the mock data.
 * This class can be suitably enhanced when interfacing the real-data from
 * the data base or from a web source.
 */
public var projectCategories: ProjectModel[];
public var projectTasks: TaskModel[];

public class DataHandler {

    /**
     * Used as the primary key for task schema within the data model.
     */
    var taskKeyGenerator: Integer  = 100;

    /**
     * Used as the primary key for project schema within the data model.
     */
    var projKeyGenerator: Integer  = 100;

    /**
     * Used to synchronize the project view with the data model.
     */
    public var updateProjectView: Boolean = false;

    /**
     * Used to synchronize the task view with the data model.
     */
    public var updateTaskView: Boolean = false;

    /**
     * Identifies the default project category name to be used
     * when the task is not assigned to any project explicitly.
     */
    public var defProjCatName: String = "Unassigned";

    init {
        addProjectCategories(
            [
            ProjectModel {
                name: "Unassigned"
                description: "Default Project for new tasks"
                key: 0
            },
            ProjectModel {
                name: "Test Development"
                description: "Developing new tests"
                key: 1
            },
            ProjectModel {
                name: "Test Execution"
                description: "Execution of tests"
                key: 2
            },
            ProjectModel {
                name: "Functional Specs"
                description: "Writing specification for new features"
                key: 3
            },
            ProjectModel {
                name: "PRD Updates"
                description: "Requirements specifications"
                key: 4
            },
            ProjectModel {
                name: "Documentation"
                description: "Product documentation"
                key: 5
            }
            ]
        );

        addProjectTasks(
            [
            TaskModel {
                category: "Test Execution"
                name: "Reliability Testing"
                priority: 3
                notes: "Testing needs to be completed by next week"
                key: 0
            },
            TaskModel {
                category: "Functional Specs"
                name: "Functional Specs Development"
                priority: 3
                notes: "Spec needs to be ready in 2 weeks"
                key: 1
            },
            TaskModel {
                category: "Test Development"
                name: "Stress Test Development"
                priority: 2
                notes: "Testing needs to be completed by 06/30"
                key: 2
            },
            TaskModel {
                category: "Test Execution"
                name: "Functional Testing"
                priority: 1
                notes: "Testing needs to be completed in 4 weeks"
                key: 3
            },
            TaskModel {
                category: "Test Execution"
                name: "PIT Testing"
                priority: 1
                notes: "Testing needs to be completed in 3 days"
                key: 4
            },
            TaskModel {
                category: "Documentation"
                name: "Tutorial Development"
                priority: 1
                notes: "Tutorial to be sent for review by next week"
                key: 5
            }
            ]
        );
    }

    /**
     * Get all the project categories.
     */
    public function getProjectCategory(): ProjectModel[] {
        return projectCategories;
    }

    /**
     * Get the task primary key for adding a new task.
     */
    function getTaskKey(): Integer {
        return taskKeyGenerator ++;
    }

    /**
     * Get the project primary key for adding a new project.
     */
    function getProjectKey(): Integer {
        return projKeyGenerator ++;
    }

    /**
     * Add a new task into the data model.
     */
    public function addProjectTask(pt: TaskModel):Integer {
        updateTaskView = false;
        var i: Integer = 0; var pos: Integer = 0;
        var key = getTaskKey();
        pt.key = key;
        if(projectTasks.size() > 0) {
            
            for(projTask in projectTasks){
                if (projTask.name == null or projTask.name == "") {
                    pos = i;
                    break;
                }
                   
                if(pt.name.compareTo(projTask.name) > 0 ) {
                    i++;
                    continue;
                } else if(pt.name.compareTo(projTask.name) <= 0) {
                    pos = i;
                    break;
                }
            }
            if(i == 0 ){
               insert pt before projectTasks[0];
            } else if( pos == 0 ){
                insert pt into projectTasks;
            } else {
                insert pt before projectTasks[pos];
            }

        } else {
            insert pt into projectTasks;
        }
        updateTaskView = true;
        return key;
    }

    /**
     * Add multiple tasks into the data model.
     */
    public function addProjectTasks(tasks: TaskModel[]):Void {
        for (task in tasks) {
            addProjectTask(task);
        }
    }

    /**
     * Add a new project category into the data model.
     */
    public function addProjectCategory(pc: ProjectModel): Boolean {
        updateProjectView = false;
        for (cat in projectCategories) {
            if (cat.name.equalsIgnoreCase(pc.name)) {
                return false;
            }
        }

        var i: Integer = 0; var pos: Integer = 0;
        var key = getProjectKey();
        pc.key = key;
        if( projectCategories.size() > 0 ) {
            for( projCate in projectCategories ){
                 if (projCate.name == null or projCate.name == "") {
                    pos = i;
                    break;
                }
                if( pc.name.compareTo(projCate.name) > 0 ) {
                    i++;
                    continue;
                } else if(pc.name.compareTo(projCate.name) <= 0) {
                    pos = i;
                    break;
                }
            }
            if(i == 0 ){
               insert pc before projectCategories[0];
            } else if( pos == 0 ){
                insert pc into projectCategories;
            } else {
                insert pc before projectCategories[pos];
            }
        } else {
            insert pc into projectCategories;
        }
        updateProjectView = true;
        return true;
    }

    /**
     * Add a sequence of project categories into the data model.
     */
    public function addProjectCategories(cats: ProjectModel[]):Void {
        for (cat in cats) {
            addProjectCategory(cat);
        }
    }

    /**
     * Update an existing project category.
     */
    public function updateProjectCategory(pCat: ProjectModel): Integer {
        for (cat in projectCategories) {
            if (cat.key != pCat.key and cat.name.equalsIgnoreCase(pCat.name)) {
                // Indicates there is another project with same name
                return 1;
            }
        }
        for(projCat in projectCategories) {
            if(projCat.key == pCat.key) {
                if (projCat.name != pCat.name) {
                    for (tasks in projectTasks) {
                        if (tasks.category.equalsIgnoreCase(projCat.name)) {
                            // Indicates there are some tasks using this project
                            return 2;
                        }
                    }
                }

                delete projCat from projectCategories;
                break;
            }
        }
        addProjectCategory(pCat);
        return 0;
    }

    /**
     * Update an existing task details.
     */
    public function updateProjectTask(pTask: TaskModel){
        for(projTas in projectTasks) {
            if(projTas.key == pTask.key) {
                delete projTas from projectTasks;
                break;
            }
        }
        addProjectTask(pTask);
    }

    /**
     * Get all the task details.
     */
    public function getProjectTasks(): TaskModel[] {
        return projectTasks;
    }

    /**
     * Get all the tasks based on the priority.
     */
    public function getProjectTasks(pr: Integer): TaskModel[] {
        var projTsks: TaskModel[];
        for(proj in projectTasks){
            if( proj.priority == pr or proj.name == null) {
                insert proj into projTsks;
            }
        }
        return projTsks;
    }

    /**
     * Get the task details for the given task name.
     */
    public function getProjectTask(projName: String): TaskModel {
        for(proj in projectTasks){
            if( proj.name == projName) {
                return proj;
            }
        }
        return null;
    }

    /**
     * Get the task details based on the primary key identifier.
     */
    public function getProjectTask(key: Integer): TaskModel {
        for (proj in projectTasks) {
            if (proj.key == key) {
                return proj;
            }
        }
        return null;
    }

    /**
     * Get all the project category names.
     */
    public function getProjectCategoriesNames(): String[] {
        var prCatNames: String[];
        for(projCat in projectCategories) {
            insert projCat.name into prCatNames;
        }
        return prCatNames;
    }

    /**
     * Get the project details for the given project name
     */
    public function getProjectCategory(catName: String): ProjectModel {
        for(projCat in projectCategories) {
            if( projCat.name == catName )
            return projCat;
        }
        return null;
    }

    /**
     * Get the project details based on the primary key identifier.
     */
    public function getProjectCategory(key: Integer): ProjectModel {
        for(projCat in projectCategories) {
            if( projCat.key == key )
            return projCat;
        }
        return null;
    }

    /**
     * Get all the task names.
     */
    public function getProjectTasksNames(): String[] {
        var prTNames: String[];
        for(projTask in projectTasks) {
            insert projTask.name into prTNames;
        }
        return prTNames;
    }

    /**
     * Get all the task names that belong to a specified project category.
     */
    public function getProjectTasksNames(projCat: String): String[] {
        var prTNames: String[];
        for(projTask in projectTasks) {
            if (projTask.category == projCat) {
                insert projTask.name into prTNames;
            }
        }
        return prTNames;
    }

    /**
     * Get the task names based on the priority.
     */
    public function getProjectTasksNames(pr: Integer): String[] {
        var prTNames: String[];
        for(projTask in projectTasks) {
            if( projTask.priority == pr or projTask.name == null ) {
                insert projTask.name into prTNames;
            }
        }
        return prTNames;
    }

    /**
     * Get the task names for the given priority and project name.
     */
    public function getProjectTasksNames(pr: Integer, projCat: String): String[] {
        var prTNames: String[];
        for(projTask in projectTasks) {
            if (projTask.category == projCat) {
                if( projTask.priority == pr or projTask.name == null ) {
                    insert projTask.name into prTNames;
                }
            }
        }
        return prTNames;
    }

    /**
     * Delete the given project category if no tasks are defined for the project.
     */
    public function deleteProjectCategory(pc: ProjectModel): Boolean {
        deleteProjectCategory(pc.key);
    }

    /**
     * Delete the project category based on the primary key identifier.
     */
    public function deleteProjectCategory(key: Integer) {
        updateProjectView = false;
        if(projectCategories.size() > 0){
            for( pcat in projectCategories) {
                if(pcat.key == key) {
                    for (task in projectTasks) {
                        if (task.category == pcat.name) {
                            return false;
                        }
                    }
                    delete pcat from projectCategories;
                    updateProjectView = true;
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Delete the project category based on the category name.
     */
    public function deleteProjectCategory(catName: String) {
        updateProjectView = false;
        if(projectCategories.size() > 0){
            for( pcat in projectCategories) {
                if(pcat.name == catName) {
                    for (task in projectTasks) {
                        if (task.category == pcat.name) {
                            return false;
                        }
                    }
                    delete pcat from projectCategories;
                    updateProjectView = true;
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Delete the given task.
     */
    public function deleteProjectTask(pt: TaskModel): Void {
        updateTaskView = false;
        if(projectTasks.size() > 0){
            for( pTask in projectTasks) {
                if(pTask.key == pt.key) {
                    delete pTask from projectTasks;
                    updateTaskView = true;
                    break;
                }
            }
        }
    }

    /**
     * Delete the task denoted by the task name.
     */
    public function deleteProjectTask(ptName: String): Void {
        updateTaskView = false;
        if(projectTasks.size() > 0){
            for( pTask in projectTasks) {
                if(pTask.name == ptName) {
                    delete pTask from projectTasks;
                    updateTaskView = true;
                    break;
                }
            }
        }
    }
}