package seedu.doist.logic.parser;

import static seedu.doist.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.doist.logic.parser.CliSyntax.PREFIX_AS;
import static seedu.doist.logic.parser.CliSyntax.PREFIX_BY;
import static seedu.doist.logic.parser.CliSyntax.PREFIX_EVERY;
import static seedu.doist.logic.parser.CliSyntax.PREFIX_FROM;
import static seedu.doist.logic.parser.CliSyntax.PREFIX_REMIND;
import static seedu.doist.logic.parser.CliSyntax.PREFIX_TO;
import static seedu.doist.logic.parser.CliSyntax.PREFIX_UNDER;

import java.util.ArrayList;
import java.util.Date;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import seedu.doist.commons.exceptions.IllegalValueException;
import seedu.doist.logic.commands.AddCommand;
import seedu.doist.logic.commands.Command;
import seedu.doist.logic.commands.IncorrectCommand;
import seedu.doist.model.tag.UniqueTagList;
import seedu.doist.model.task.Description;
import seedu.doist.model.task.Priority;
import seedu.doist.model.task.Task;

/**
 * Parses input arguments and creates a new AddCommand object
 */
public class AddCommandParser {

    private static final Pattern ADD_COMMAND_REGEX = Pattern.compile("(?<preamble>[^\\\\]*)" +
                                                                     "(?<parameters>((\\\\)(\\S+)(\\s+)([^\\\\]*))*)");

    /**
     * Parses the given {@code String} of arguments in the context of the AddCommand
     * and returns an AddCommand object for execution.
     */
    public Command parse(String args) {
        final Matcher matcher = ADD_COMMAND_REGEX.matcher(args.trim());
        if (!matcher.matches() || args.trim().equals("")) {
            return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
        }

        final String preamble = matcher.group("preamble");
        final String parameters = matcher.group("parameters").trim();
        ArrayList<String> tokens = ParserUtil.getParameterKeysFromString(parameters);

        ArgumentTokenizer argsTokenizer = new ArgumentTokenizer(PREFIX_FROM, PREFIX_TO, PREFIX_REMIND, PREFIX_EVERY,
                                                                PREFIX_AS, PREFIX_BY, PREFIX_UNDER);

        if (!argsTokenizer.validateTokens(tokens) || (argsTokenizer.validateDate(tokens) == -1)) {
            return new IncorrectCommand(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
        }

        argsTokenizer.tokenize(parameters);

        try {
            Task taskToAdd = createTaskFromParameters(preamble, argsTokenizer);
            return new AddCommand(taskToAdd);
        } catch (IllegalValueException ive) {
            return new IncorrectCommand(ive.getMessage());
        }
    }

    /**
     * Creates a task from raw values of parameters.
     *
     * @throws IllegalValueException
     *             if any of the raw values are invalid
     */
    private Task createTaskFromParameters(String preamble, ArgumentTokenizer tokenizer) throws IllegalValueException {
        if (preamble == null || preamble.trim().isEmpty()) {
            throw new IllegalValueException(AddCommand.MESSAGE_NO_DESC);
        }

        UniqueTagList tagList = new UniqueTagList();

        // create task with specified tags
        Optional<String> tagsParameterString = tokenizer.getValue(PREFIX_UNDER);
        if (tagsParameterString.isPresent()) {
            tagList = ParserUtil.parseTagsFromString(tagsParameterString.get());
        }

        Date startDate = null, endDate = null;
        Optional<String> from = tokenizer.getValue(PREFIX_FROM);
        Optional<String> to = tokenizer.getValue(PREFIX_TO);
        if (from.isPresent() && to.isPresent()) {
            startDate = ParserUtil.parseDate(from.toString());
            endDate =  ParserUtil.parseDate(to.toString());
        }

        Task toAdd = new Task(new Description(preamble), tagList, startDate, endDate);
        // set priority
        Optional<Priority> priority = ParserUtil.parsePriority(tokenizer.getValue(PREFIX_AS));
        if (priority.isPresent()) {
            toAdd.setPriority(priority.get());
        }
        return toAdd;
    }
}

@@ -2309,16 +2309,32 @@
 kens) %7C%7C
+%0A               
  (argsTo
@@ -2369,10 +2369,38 @@
  == 
--1
+ArgumentTokenizer.DATE_INVALID
 )) %7B
@@ -3641,239 +3641,396 @@
     
-Optional%3CString%3E from = tokenizer.getValue(PREFIX_FROM);%0A        Optional%3CString%3E to = tokenizer.getValue(PREFIX_TO);%0A        if (from.isPresent() && to.isPresent()) %7B%0A            startDate = ParserUtil.parseDate(from.toString());%0A
+int dateFormat = tokenizer.getDateFormat();%0A        switch (dateFormat) %7B%0A        case ArgumentTokenizer.DATE_NIL : break;%0A        case ArgumentTokenizer.DATE_BY :  endDate = ParserUtil.parseDate(tokenizer.getValue(PREFIX_BY).get()); break;%0A        case ArgumentTokenizer.DATE_FROM : startDate = ParserUtil.parseDate(tokenizer.getValue(PREFIX_FROM).get());%0A                               
     
@@ -4046,17 +4046,16 @@
 ndDate =
- 
  ParserU
@@ -4074,20 +4074,112 @@
 e(to
-.toString())
+kenizer.getValue(PREFIX_TO).get());%0A                                           break;%0A        default : 
 ;%0A  

Include method to parse Date