/*
 * Copyright (c) 2013-2015 Cinchapi, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cinchapi.concourse.lang;

import java.text.MessageFormat;
import java.util.List;

import org.cinchapi.concourse.thrift.TCriteria;
import org.cinchapi.concourse.thrift.TSymbol;
import org.cinchapi.concourse.thrift.TSymbolType;

import com.google.common.collect.Lists;

/**
 * Tools for translating aspects of the language.
 * 
 * @author Jeff Nelson
 */
public final class Translate {

    /**
     * Translate the {@link tsymbol} to its Java analog.
     * 
     * @param tsymbol
     * @return the analogous Symbol
     */
    public static Symbol fromThrift(TSymbol tsymbol) {
        if(tsymbol.getType() == TSymbolType.CONJUNCTION) {
            return ConjunctionSymbol.valueOf(tsymbol.getSymbol().toUpperCase());
        }
        else if(tsymbol.getType() == TSymbolType.KEY) {
            return KeySymbol.parse(tsymbol.getSymbol());
        }
        else if(tsymbol.getType() == TSymbolType.VALUE) {
            return ValueSymbol.parse(tsymbol.getSymbol());
        }
        else if(tsymbol.getType() == TSymbolType.PARENTHESIS) {
            return ParenthesisSymbol.parse(tsymbol.getSymbol());
        }
        else if(tsymbol.getType() == TSymbolType.OPERATOR) {
            return OperatorSymbol.parse(tsymbol.getSymbol());
        }
        else if(tsymbol.getType() == TSymbolType.TIMESTAMP) {
            return TimestampSymbol.parse(tsymbol.getSymbol());
        }
        else {
            throw new IllegalArgumentException("Unrecognized TSymbol "
                    + tsymbol);
        }
    }

    /**
     * Translate the {@code criteria} to its Thrift analog.
     * 
     * @param criteria
     * @return the analogous TCriteria
     */
    public static TCriteria toThrift(Criteria criteria) {
        List<TSymbol> symbols = Lists.newArrayList();
        for (Symbol symbol : criteria.getSymbols()) {
            symbols.add(toThrift(symbol));
        }
        return new TCriteria(symbols);
    }

    /**
     * Translate {@code symbol} to its Thrift analog.
     * 
     * @param symbol
     * @return The analogous TSymbol
     */
    public static TSymbol toThrift(Symbol symbol) {
        if(symbol.getClass() == ConjunctionSymbol.class) {
            return new TSymbol(TSymbolType.CONJUNCTION, symbol.toString());
        }
        else if(symbol.getClass() == KeySymbol.class) {
            return new TSymbol(TSymbolType.KEY, symbol.toString());
        }
        else if(symbol.getClass() == ValueSymbol.class) {
            return new TSymbol(TSymbolType.VALUE, escape(symbol.toString()));
        }
        else if(symbol.getClass() == ParenthesisSymbol.class) {
            return new TSymbol(TSymbolType.PARENTHESIS, symbol.toString());
        }
        else if(symbol.getClass() == OperatorSymbol.class) {
            return new TSymbol(TSymbolType.OPERATOR, symbol.toString());
        }
        else if(symbol.getClass() == TimestampSymbol.class) {
            return new TSymbol(TSymbolType.TIMESTAMP, symbol.toString());
        }
        else {
            throw new IllegalArgumentException(MessageFormat.format(
                    "Cannot translate {0} to Thrift", symbol));
        }
    }

    /**
     * Do any escaping of the {@code value} in order to preserve it during the
     * translation.
     * 
     * @param value
     * @return the escaped value
     */
    private static String escape(String value) {
        if(value.matches("`([^`]+)`")) { // CON-167: surround by quotes so the
                                         // backticks are not interpreted as
                                         // indicators of an encoded Tag. This
                                         // case would happen if the user
                                         // manually placed text wrapped in
                                         // backticks in the Criteria instead of
                                         // using the #Tag.create() method.
            return "\"" + value + "\"";
        }
        else {
            return value;
        }
    }

    private Translate() {/* noop */}

}

@@ -982,24 +982,23 @@
 l class 
-Translat
+Languag
 e %7B%0A%0A   
@@ -1158,17 +1158,26 @@
  Symbol 
-f
+translateF
 romThrif
@@ -2314,23 +2314,40 @@
 iteria t
-oThrift
+ranslateToThriftCriteria
 (Criteri
@@ -2493,23 +2493,38 @@
 ls.add(t
+ranslateT
 oThrift
+Symbol
 (symbol)
@@ -2745,23 +2745,38 @@
 Symbol t
+ranslateT
 oThrift
+Symbol
 (Symbol 
@@ -4702,24 +4702,23 @@
 private 
-Translat
+Languag
 e() %7B/* 

rename methods