package com.automattic.simplenote.utils;

public class SearchTokenizer {

    static public final String EMPTY = "";

    static public final char LITERAL = '/';
    static public final char SPACE = ' ';
    static public final char DOUBLE_QUOTE = '"';
    static public final char SINGLE_QUOTE = '\'';
    static public final char GLOB = '*';
    static public final char COLON = ':';
    static public final char ESCAPE = '\\';
    static public final char HYPHEN = '-';

    private String mRawQuery;

    public SearchTokenizer(String query) {
        mRawQuery = query;
    }

    private String parseQuery() {
        if (mRawQuery == null || mRawQuery.equals(EMPTY)) {
            return EMPTY;
        }

        StringBuilder query = new StringBuilder(mRawQuery.length());

        // iterate through each character
        int length = mRawQuery.length();

        // if we have an open " or not
        boolean inStrictTerm = false;

        // if we've detected a search term
        boolean inTerm = false;

        // if we're doing a literal query
        boolean isLiteral = false;

        // if the current char is a single or double quote
        boolean isQuoteChar;

        // if the previous char was an escape char
        boolean isEscaped = false;

        boolean hasHyphen = false;

        // the current character
        char current = '\0', last, quoteChar = '\0';

        for (int position = 0; position < length; position++) {

            last = current;
            current = mRawQuery.charAt(position);

            // if the last character was an \ and we weren't already escaped
            isEscaped = last == ESCAPE && !isEscaped;
            // if it's a ' or " and it isn't be escaped
            isQuoteChar = !isEscaped && (current == SINGLE_QUOTE || current == DOUBLE_QUOTE);

            // if query starts with / we're just going to give the complete query
            if (position == 0 && current == LITERAL && length > 1) {
                isLiteral = true;
                continue;
            }

            // we're inside a quoted section and have found another quote, append and loop
            if (inStrictTerm && current == quoteChar) {
                query.append(current);
                inStrictTerm = false;
                inTerm = false;
                continue;
            }

            // we're in a strict term and it's not a ", so append and continue
            if (inStrictTerm) {
                query.append(current);
                continue;
            }

            // we've found a matching end quote
            if (isQuoteChar) {
                quoteChar = current;
                // we were already in a term so end it with a glob
                if (inTerm && !isLiteral) query.append(new char[]{GLOB, SPACE});
                // start the strict term
                query.append(current);
                inStrictTerm = true;
                inTerm = true;
                continue;
            }

            if (current == COLON && inTerm) {
                inTerm = false;
                query.append(current);
                continue;
            }

            if (current == HYPHEN && last != SPACE && position != 0) {
                // If we have a hyphen character between two terms, with no space between them
                String space = Character.toString(SPACE);
                String lastCharacter = Character.toString(last);
                int tokenStartIndex = query.lastIndexOf(space, query.indexOf(lastCharacter));
                query.insert(Math.max(0, tokenStartIndex + 1), DOUBLE_QUOTE);
                query.append(current);
                hasHyphen = true;
                continue;
            }

            if (current == SPACE) {
                if (inTerm && !isLiteral) query.append(GLOB);
                if (hasHyphen) query.append(DOUBLE_QUOTE);
                query.append(current);
                inTerm = false;
                hasHyphen = false;
                continue;
            }

            inTerm = true;
            query.append(current);

        }

        // close the strict term
        if (inStrictTerm) query.append(quoteChar);
        if (inTerm && !inStrictTerm && !isLiteral) query.append(GLOB);
        if (hasHyphen) query.append(DOUBLE_QUOTE);

        return query.toString();
    }

    @Override
    public String toString() {
        return parseQuery();
    }


}
