// Path: src/main/java/com/wanasit/chrono/ChronoOption.java
// public class ChronoOption {
// 
//     public static final ChronoOption sharedOptions = standardOptions();
// 
//     public final List<Parser> parsers = new ArrayList<Parser>();
//     public final List<Refiner> refiners = new ArrayList<Refiner>();
// 
//     public final Map<String, Integer> timezoneMap = new HashMap<String, Integer>();
//     public Integer timezoneOffset = null;
// 
//     private ChronoOption() {
//         this.timezoneOffset = Calendar.getInstance().getTimeZone().getOffset(0);
//     }
// 
//     public static ChronoOption standardOptions() {
//         ChronoOption options = new ChronoOption();
// 
//         // All Parsers
//         options.parsers.add(new ENInternationalStandardParser());
//         options.parsers.add(new ENMonthNameLittleEndianParser());
//         options.parsers.add(new ENMonthNameMiddleEndianParser());
//         options.parsers.add(new ENSlashBigEndianDateFormatParser());
//         options.parsers.add(new ENSlashDateFormatParser());
//         options.parsers.add(new ENTimeDeadlineFormatParser());
//         options.parsers.add(new ENTimeAgoFormatParser());
//         options.parsers.add(new ENTimeExpressionParser());
//         options.parsers.add(new JPStandartDateFormatParser());
//         options.parsers.add(new JPDayOfWeekDateFormatParser());
//         options.parsers.add(new JPDateAgoFormatParser());
//         options.parsers.add(new JPTimeExpressionParser());
// 
//         // Standard Pipeline
//         options.refiners.add(new PrefixCheckFilter());
//         options.refiners.add(new ENRemoveOverlapRefiner());
//         options.refiners.add(new ENMergeDateAndTimeRefiner());
//         options.refiners.add(new ENMergeDateRangeRefiner());
//         options.refiners.add(new LowProbabilityFormatFilter());
//         options.refiners.add(new ExtractTimezoneRefiner());
//         options.refiners.add(new ExtractConcordanceRefiner());
// 
//         return options;
//     }
// 
//     public static ChronoOption casualOptions() {
// 
//         ChronoOption options = ChronoOption.standardOptions();
//         options.parsers.add(new ENCasualDateExpressionParser());
//         options.parsers.add(new ENDayOfWeekDateFormatParser());
//         options.parsers.add(new ENWeekExpressionParser());
//         options.parsers.add(new JPCasualDateExpressionParser());
// 
//         options.refiners.add(2, new ENMergeWeekdayRefiner());
// 
//         return options;
//     }
// 
// 
// }
// 
// Path: src/main/java/com/wanasit/chrono/ParsedResult.java
// public class ParsedResult implements Comparable<ParsedResult>, Cloneable{
//     
//     public int index;
//     public String text;
//     public String concordance;
//     
//     public ParsedDateComponent start;
//     public ParsedDateComponent end;
// 
//     public final Set<String> tags = new HashSet<String>();
// 
//     public ParsedResult() { 
//         this.start = new ParsedDateComponent();
//     }
//     
//     public ParsedResult(int index, String text) { 
//         this.index = index;
//         this.text  = text;
//         this.start = new ParsedDateComponent();
//     }
// 
//     public ParsedResult(Object source, int index, String text) {
//         this(index, text);
//         this.tags.add(source.getClass().getName());
//     }
//     
//     
//     public int compareTo(ParsedResult o) {
//         return this.index - o.index;
//     }
//     
//     
//     protected static final SimpleDateFormat PRINT_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm");
//     
//     @Override
//     public String toString() {
//         return "ParsedResult: \"" + this.text + "\" > "+ PRINT_FORMAT.format(this.start.date()) + 
//                 ((this.end != null)? (" - " +PRINT_FORMAT.format(this.end.date())) : "");
//     }
// }
// 
// Path: src/main/java/com/wanasit/chrono/refiner/Refiner.java
// public interface Refiner {
//     
//     List<ParsedResult> refine(List<ParsedResult> results, String text, ChronoOption options);
// }


import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.wanasit.chrono.ChronoOption;
import com.wanasit.chrono.ParsedResult;
import com.wanasit.chrono.refiner.Refiner;
package com.wanasit.chrono.parser;




public abstract class ParserAbstract implements Parser {

    protected final List<Refiner> refiners = new ArrayList<Refiner>();

    protected abstract Pattern pattern();

    protected abstract ParsedResult extract(String text, Date refDate, Matcher matcher, ChronoOption option);

    public List<ParsedResult> execute(String text, Date refDate, ChronoOption options) {

        List<ParsedResult> results = new LinkedList<ParsedResult>();

        int searchingIndex = 0;
        Matcher matcher = this.pattern().matcher(text);

        while (searchingIndex < text.length() && matcher.find(searchingIndex)) {

            ParsedResult result = this.extract(text, refDate, matcher, options);

            if (result == null) {
                // Failed to extract the date result, MOVE ON
                searchingIndex = matcher.start() + 1;
                continue;
            }

            searchingIndex = result.index + result.text.length() + 1;
            results.add(result);
        }

// Path: src/main/java/com/wanasit/chrono/ChronoOption.java
// public class ChronoOption {
// 
//     public static final ChronoOption sharedOptions = standardOptions();
// 
//     public final List<Parser> parsers = new ArrayList<Parser>();
//     public final List<Refiner> refiners = new ArrayList<Refiner>();
// 
//     public final Map<String, Integer> timezoneMap = new HashMap<String, Integer>();
//     public Integer timezoneOffset = null;
// 
//     private ChronoOption() {
//         this.timezoneOffset = Calendar.getInstance().getTimeZone().getOffset(0);
//     }
// 
//     public static ChronoOption standardOptions() {
//         ChronoOption options = new ChronoOption();
// 
//         // All Parsers
//         options.parsers.add(new ENInternationalStandardParser());
//         options.parsers.add(new ENMonthNameLittleEndianParser());
//         options.parsers.add(new ENMonthNameMiddleEndianParser());
//         options.parsers.add(new ENSlashBigEndianDateFormatParser());
//         options.parsers.add(new ENSlashDateFormatParser());
//         options.parsers.add(new ENTimeDeadlineFormatParser());
//         options.parsers.add(new ENTimeAgoFormatParser());
//         options.parsers.add(new ENTimeExpressionParser());
//         options.parsers.add(new JPStandartDateFormatParser());
//         options.parsers.add(new JPDayOfWeekDateFormatParser());
//         options.parsers.add(new JPDateAgoFormatParser());
//         options.parsers.add(new JPTimeExpressionParser());
// 
//         // Standard Pipeline
//         options.refiners.add(new PrefixCheckFilter());
//         options.refiners.add(new ENRemoveOverlapRefiner());
//         options.refiners.add(new ENMergeDateAndTimeRefiner());
//         options.refiners.add(new ENMergeDateRangeRefiner());
//         options.refiners.add(new LowProbabilityFormatFilter());
//         options.refiners.add(new ExtractTimezoneRefiner());
//         options.refiners.add(new ExtractConcordanceRefiner());
// 
//         return options;
//     }
// 
//     public static ChronoOption casualOptions() {
// 
//         ChronoOption options = ChronoOption.standardOptions();
//         options.parsers.add(new ENCasualDateExpressionParser());
//         options.parsers.add(new ENDayOfWeekDateFormatParser());
//         options.parsers.add(new ENWeekExpressionParser());
//         options.parsers.add(new JPCasualDateExpressionParser());
// 
//         options.refiners.add(2, new ENMergeWeekdayRefiner());
// 
//         return options;
//     }
// 
// 
// }
// 
// Path: src/main/java/com/wanasit/chrono/ParsedResult.java
// public class ParsedResult implements Comparable<ParsedResult>, Cloneable{
//     
//     public int index;
//     public String text;
//     public String concordance;
//     
//     public ParsedDateComponent start;
//     public ParsedDateComponent end;
// 
//     public final Set<String> tags = new HashSet<String>();
// 
//     public ParsedResult() { 
//         this.start = new ParsedDateComponent();
//     }
//     
//     public ParsedResult(int index, String text) { 
//         this.index = index;
//         this.text  = text;
//         this.start = new ParsedDateComponent();
//     }
// 
//     public ParsedResult(Object source, int index, String text) {
//         this(index, text);
//         this.tags.add(source.getClass().getName());
//     }
//     
//     
//     public int compareTo(ParsedResult o) {
//         return this.index - o.index;
//     }
//     
//     
//     protected static final SimpleDateFormat PRINT_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm");
//     
//     @Override
//     public String toString() {
//         return "ParsedResult: \"" + this.text + "\" > "+ PRINT_FORMAT.format(this.start.date()) + 
//                 ((this.end != null)? (" - " +PRINT_FORMAT.format(this.end.date())) : "");
//     }
// }
// 
// Path: src/main/java/com/wanasit/chrono/refiner/Refiner.java
// public interface Refiner {
//     
//     List<ParsedResult> refine(List<ParsedResult> results, String text, ChronoOption options);
// }


// Path: src/main/java/com/wanasit/chrono/parser/ParserAbstract.java
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.wanasit.chrono.ChronoOption;
import com.wanasit.chrono.ParsedResult;
import com.wanasit.chrono.refiner.Refiner;

package com.wanasit.chrono.parser;




public abstract class ParserAbstract implements Parser {

    protected final List<Refiner> refiners = new ArrayList<Refiner>();

    protected abstract Pattern pattern();

    protected abstract ParsedResult extract(String text, Date refDate, Matcher matcher, ChronoOption option);

    public List<ParsedResult> execute(String text, Date refDate, ChronoOption options) {

        List<ParsedResult> results = new LinkedList<ParsedResult>();

        int searchingIndex = 0;
        Matcher matcher = this.pattern().matcher(text);

        while (searchingIndex < text.length() && matcher.find(searchingIndex)) {

            ParsedResult result = this.extract(text, refDate, matcher, options);

            if (result == null) {
                // Failed to extract the date result, MOVE ON
                searchingIndex = matcher.start() + 1;
                continue;
            }

            searchingIndex = result.index + result.text.length() + 1;
            results.add(result);
        }

        for (Refiner refiner : this.refiners) {