com.the.todo.Logic.java Source code

Java tutorial

Introduction

Here is the source code for com.the.todo.Logic.java

Source

/**
 * This file is part of TheTODO, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2014 TheTODO
 * Copyright (c) Poh Wei Cheng <calvinpohwc@gmail.com>
 *             Chen Kai Hsiang <kaihsiang95@gmail.com>
 *             Khin Wathan Aye <y.caiyun@gmail.com>
 *             Neo Eng Tai <neoengtai@gamil.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.the.todo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.UUID;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.joda.time.LocalDate;

import com.the.todo.command.CommandStatus;
import com.the.todo.command.CommandStatus.Status;
import com.the.todo.command.ToDoAdd;
import com.the.todo.command.ToDoCommand;
import com.the.todo.command.ToDoComplete;
import com.the.todo.command.ToDoDelete;
import com.the.todo.command.ToDoEdit;
import com.the.todo.command.ToDoIncomplete;
import com.the.todo.command.ToDoSearch;
import com.the.todo.command.ToDoUndo;
import com.the.todo.command.ToDoView;
import com.the.todo.io.FileHandler;
import com.the.todo.model.ToDo;
import com.the.todo.model.ToDo.Type;
import com.the.todo.storage.JsonFileStore;
import com.the.todo.storage.ToDoStore;
import com.the.todo.util.CommandUtil;

public class Logic {

    private ToDoStore todoStorage;

    private List<ToDo> todoDisplay;
    private Map<DateCategory, List<ToDo>> todoMapDisplay;
    private List<UUID> todoIdStorage;
    private Stack<ToDoCommand> undoStack;
    private CommandType lastCommand;
    private DisplayType displayType;
    private ToDo lastChangedTodo;

    private static Logic logic = null;
    private static final String FILENAME = "thetodo.json";
    private static final Logger LOG = LogManager.getLogger(Logic.class);

    public static enum CommandType {
        ADD, VIEW, EDIT, DELETE, COMPLETE, INCOMPLETE, SEARCH, UNDO, INVALID
    };

    public static enum DisplayType {
        ALL, SEARCH
    };

    public static enum DateCategory {
        OVERDUE, TODAY, TOMORROW, UPCOMING, SOMEDAY
    }

    public Logic() {
        todoStorage = new JsonFileStore(FILENAME);
        todoDisplay = new ArrayList<ToDo>();
        todoMapDisplay = new LinkedHashMap<DateCategory, List<ToDo>>();
        todoIdStorage = new ArrayList<UUID>();
        undoStack = new Stack<ToDoCommand>();
        lastCommand = null;
        displayType = DisplayType.ALL;
        lastChangedTodo = null;

        initializeDisplayList();
        updateDisplayItems(todoStorage.getAll());
    }

    public static Logic getInstance() {
        if (logic == null) {
            logic = new Logic();
        }

        return logic;
    }

    public ToDoStore getTodoStorage() {
        return todoStorage;
    }

    public Map<DateCategory, List<ToDo>> getToDoMapDisplay() {
        return todoMapDisplay;
    }

    public CommandStatus processCommand(String input) {
        String originlCommand = CommandUtil.getFirstPhrase(input);
        String command = originlCommand.toLowerCase();
        String params = CommandUtil.getParams(originlCommand, input);
        CommandType commandType = getCommandType(command);
        boolean isSingleChange = false;

        LOG.info("Inputs: [" + input + "].");

        ToDoCommand todoCommand = null;
        displayType = DisplayType.ALL;

        CommandStatus commandStatus;

        switch (commandType) {
        case ADD:
            todoCommand = new ToDoAdd(todoStorage, params);
            isSingleChange = true;
            break;
        case VIEW:
            todoCommand = new ToDoView(todoStorage, todoDisplay, params);
            displayType = DisplayType.SEARCH;
            break;
        case EDIT:
        case DELETE:
        case COMPLETE:
        case INCOMPLETE:
            try {
                todoCommand = parseToDoCommand(commandType, params);
            } catch (Exception e) {
                commandType = CommandType.INVALID;
                commandStatus = new CommandStatus(Status.INVALID, "Invalid command.");
            }
            isSingleChange = true;
            break;
        case SEARCH:
            todoCommand = new ToDoSearch(todoStorage, todoDisplay, params);
            displayType = DisplayType.SEARCH;
            break;
        case UNDO:
            todoCommand = new ToDoUndo(todoStorage, undoStack);
            isSingleChange = true;
            break;
        case INVALID:
            break;
        default:
            break;
        }

        if (commandType != CommandType.INVALID) {
            commandStatus = todoCommand.execute();
            todoStorage.saveToFile();

            if (displayType == DisplayType.ALL)
                updateDisplayItems(todoStorage.getAll());
            else
                updateDisplayItems(todoDisplay);

            if (todoCommand.isUndoable() && commandStatus.getStatus() == Status.SUCCESS) {
                undoStack.push(todoCommand);
            }

            lastCommand = commandType;

            if (isSingleChange) {
                lastChangedTodo = todoCommand.getTodo();
            } else {
                lastChangedTodo = null;
            }

        } else {
            commandStatus = new CommandStatus(Status.INVALID, "Invalid command.");
        }

        System.out.println("-----------------------------");
        for (ToDo todo : todoStorage.getAll()) {
            System.out.println("ID: " + todo.getId());
            System.out.println("Type: " + todo.getType());
            System.out.println("Title: " + todo.getTitle());
            System.out.println("Start Date: " + todo.getStartDate());
            System.out.println("End Date: " + todo.getEndDate());
            System.out.println("Category: " + todo.getCategory());
            System.out.println("Completed: " + todo.isCompleted());
            System.out.println("Delete: " + todo.isDeleted());
            System.out.println("Priority: " + todo.getPriority());
        }
        System.out.println("--------Completed---------");
        for (ToDo todo : todoStorage.getAllCompleted()) {
            System.out.println("ID: " + todo.getId());
            System.out.println("Type: " + todo.getType());
            System.out.println("Title: " + todo.getTitle());
            System.out.println("Start Date: " + todo.getStartDate());
            System.out.println("End Date: " + todo.getEndDate());
            System.out.println("Category: " + todo.getCategory());
            System.out.println("Completed: " + todo.isCompleted());
            System.out.println("Delete: " + todo.isDeleted());
            System.out.println("Priority: " + todo.getPriority());
        }
        System.out.println("--------UnCompleted---------");
        for (ToDo todo : todoStorage.getAllUncompleted()) {
            System.out.println("ID: " + todo.getId());
            System.out.println("Type: " + todo.getType());
            System.out.println("Title: " + todo.getTitle());
            System.out.println("Start Date: " + todo.getStartDate());
            System.out.println("End Date: " + todo.getEndDate());
            System.out.println("Category: " + todo.getCategory());
            System.out.println("Completed: " + todo.isCompleted());
            System.out.println("Delete: " + todo.isDeleted());
            System.out.println("Priority: " + todo.getPriority());
        }

        LOG.info("System Message: [" + commandStatus.getMessage() + "].");

        return commandStatus;
    }

    CommandType getCommandType(String input) {

        if (input.trim().isEmpty()) {
            return CommandType.INVALID;
        }

        String command = CommandUtil.getFirstPhrase(input);

        switch (command) {
        case "a":
        case "add":
            return CommandType.ADD;
        case "v":
        case "view":
            return CommandType.VIEW;
        case "e":
        case "edit":
            return CommandType.EDIT;
        case "d":
        case "rm":
        case "del":
        case "delete":
            return CommandType.DELETE;
        case "c":
        case "done":
        case "complete":
            return CommandType.COMPLETE;
        case "incomplete":
            return CommandType.INCOMPLETE;
        case "s":
        case "search":
            return CommandType.SEARCH;
        case "u":
        case "undo":
            return CommandType.UNDO;
        default:
            return CommandType.INVALID;
        }
    }

    private void sortByDate(Map<DateCategory, List<ToDo>> todoMap, List<ToDo> todoList) {
        todoMap.clear();

        Type todoType;
        LocalDate startDate;
        LocalDate endDate;
        LocalDate today = new LocalDate();
        LocalDate tomorrow = new LocalDate().plusDays(1);

        List<ToDo> todoOverdue = new ArrayList<ToDo>();
        List<ToDo> todoToday = new ArrayList<ToDo>();
        List<ToDo> todoTomorrow = new ArrayList<ToDo>();
        List<ToDo> todoUpcoming = new ArrayList<ToDo>();
        List<ToDo> todoSomeday = new ArrayList<ToDo>();

        for (ToDo todo : todoList) {
            todoType = todo.getType();
            startDate = todo.getStartDate().toLocalDate();
            endDate = todo.getEndDate().toLocalDate();

            if (todoType == Type.FLOATING) {
                todoSomeday.add(todo);
            }

            if (todoType == Type.DEADLINE) {
                if (endDate.isBefore(today)) {
                    todoOverdue.add(todo);
                } else if (endDate.equals(today)) {
                    todoToday.add(todo);
                } else if (endDate.equals(tomorrow)) {
                    todoTomorrow.add(todo);
                }
            }

            if (todoType == Type.TIMED) {
                if (endDate.isBefore(today)) {
                    todoOverdue.add(todo);
                }
                if (!today.isBefore(startDate) && !today.isAfter(endDate)) {
                    todoToday.add(todo);
                }
                if (!tomorrow.isBefore(startDate) && !tomorrow.isAfter(endDate)) {
                    todoTomorrow.add(todo);
                }
            }

            if (displayType == DisplayType.SEARCH) {
                if (todoType == Type.DEADLINE) {
                    if (endDate.isAfter(tomorrow)) {
                        todoUpcoming.add(todo);
                    }
                } else if (todoType == Type.TIMED) {
                    if (endDate.isAfter(tomorrow)) {
                        todoUpcoming.add(todo);
                    }
                }
            }
        }

        if (todoOverdue.size() > 0) {
            todoMap.put(DateCategory.OVERDUE, todoOverdue);
        }
        if (todoToday.size() > 0) {
            todoMap.put(DateCategory.TODAY, todoToday);
        }
        if (todoTomorrow.size() > 0) {
            todoMap.put(DateCategory.TOMORROW, todoTomorrow);
        }
        if (todoUpcoming.size() > 0) {
            todoMap.put(DateCategory.UPCOMING, todoUpcoming);
        }
        if (todoSomeday.size() > 0) {
            todoMap.put(DateCategory.SOMEDAY, todoSomeday);
        }

        for (Entry<DateCategory, List<ToDo>> entry : todoMap.entrySet()) {
            Collections.sort(entry.getValue());
        }
    }

    private void updateIdStorage(List<UUID> todoIdStorage, Map<DateCategory, List<ToDo>> todoMap) {
        if (todoMap == null || todoMap.isEmpty()) {
            return;
        }

        todoIdStorage.clear();

        for (Entry<DateCategory, List<ToDo>> entry : todoMap.entrySet()) {
            for (ToDo todo : entry.getValue()) {
                todoIdStorage.add(todo.getId());
            }
        }
    }

    private void initializeDisplayList() {
        todoDisplay.clear();

        for (ToDo item : todoStorage.getAll()) {
            todoDisplay.add(new ToDo(item));
        }
    }

    private void updateDisplayItems(List<ToDo> list) {
        sortByDate(todoMapDisplay, list);
        updateIdStorage(todoIdStorage, todoMapDisplay);
    }

    private ToDoCommand parseToDoCommand(CommandType commandType, String input) throws Exception {

        String index = CommandUtil.getFirstPhrase(input);
        String params = CommandUtil.getParams(index, input);

        try {
            UUID id = getId(Integer.valueOf(index));
            ToDo todo = getToDo(id);

            if (todo == null) {
                throw new Exception("Invalid ID.");
            }

            switch (commandType) {
            case EDIT:
                return new ToDoEdit(todoStorage, todo, params);
            case DELETE:
                return new ToDoDelete(todoStorage, todo);
            case COMPLETE:
                return new ToDoComplete(todoStorage, todo);
            case INCOMPLETE:
                return new ToDoIncomplete(todoStorage, todo);
            default:
                return null;
            }
        } catch (NumberFormatException ex) {
            throw new Exception("Invalid Command.");
        }
    }

    private ToDo getToDo(UUID id) {
        ToDo todo = null;

        if (id != null) {
            for (ToDo item : todoStorage.getAll()) {
                if (item.getId().equals(id)) {
                    todo = item;
                    break;
                }
            }
        }

        return todo;
    }

    private UUID getId(int index) {
        UUID id;

        try {
            id = todoIdStorage.get(index - 1);
        } catch (IndexOutOfBoundsException ex) {
            id = null;
        }

        return id;
    }

    public CommandType getLastCommand() {
        return lastCommand;
    }

    public DisplayType getDisplayType() {
        return displayType;
    }

    public ToDo getLastChangedToDo() {
        return lastChangedTodo;
    }

}