/*
 * Copyright 2013 EK3 Technologies, 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 ei.ne.ke.cassandra.cql3.template;

import java.util.Collection;

import org.apache.commons.lang.StringUtils;

import com.google.common.base.Functions;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;

/**
 * Builder for CQL3 INSERT statements.
 */
public class InsertStatementBuilder implements Mutating {

    private Identifier table;
    private Collection<Identifier> selection;
    private Collection<Term> values;
    private Collection<Option> options;
    private boolean usingTimestamp;

    /**
     * Constructor.
     */
    InsertStatementBuilder() {
        this.table = null;
        this.selection = Lists.newArrayList();
        this.values = Lists.newArrayList();
        this.options = Lists.newArrayList();
        this.usingTimestamp = false;
    }

    /**
     * Sets the table to insert into.
     * @param identifier the table to insert into.
     * @return this builder.
     */
    public InsertStatementBuilder into(String identifier) {
        this.table = new Identifier(identifier);
        return this;
    }

    /**
     *
     *
     * @param columns
     * @return
     */
    public InsertStatementBuilder columns(String... columns) {
        if (columns != null) {
            for (String column : columns) {
                selection.add(new Identifier(column));
            }
        }
        return this;
    }

    /**
     *
     *
     * @param value
     * @return this builder.
     */
    public InsertStatementBuilder columns(Collection<String> columns) {
        if (columns != null) {
            for (String column : columns) {
                selection.add(new Identifier(column));
            }
        }
        return this;
    }

    /**
     *
     *
     * @param termOrLiteral
     * @return this builder.
     */
    public InsertStatementBuilder values(String... termsOrLiterals) {
        for (String termOrLiteral : termsOrLiterals) {
            values.add(new Term(termOrLiteral));
        }
        return this;
    }

    /**
     *
     *
     * @param column
     * @return this builder.
     */
    public InsertStatementBuilder values(Collection<String> termOrLiterals) {
        if (termOrLiterals != null) {
            for (String termOrLiteral : termOrLiterals) {
                values.add(new Term(termOrLiteral));
            }
        }
        return this;
    }

    /**
     *
     *
     * @param timestamp
     * @return this builder.
     */
    public InsertStatementBuilder usingTimestamp(long timestamp) {
        options.add(Option.timestamp(timestamp));
        usingTimestamp = true;
        return this;
    }

    /**
     *
     *
     * @param ttl
     * @return this builder.
     */
    public InsertStatementBuilder usingTtl(long ttl) {
        options.add(Option.ttl(ttl));
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String build() {
        Preconditions.checkNotNull(table, "You must set the name of a table");
        StringBuilder sb = new StringBuilder();
        sb.append("INSERT INTO ");
        sb.append(table);
        if (!selection.isEmpty()) {
            sb.append(" (");
            sb.append(StringUtils.join(Collections2.transform(selection, Functions.toStringFunction()), ", "));
            sb.append(") VALUES (");
            while (values.size() < selection.size()) {
                values.add(Term.VARIABLE);
            }
            sb.append(StringUtils.join(Collections2.transform(values, Functions.toStringFunction()), ", "));
            sb.append(")");
        }
        if (!options.isEmpty()) {
            sb.append(" USING ");
            sb.append(StringUtils.join(Collections2.transform(options, Functions.toStringFunction()), " AND "));
        }
        sb.append(";");
        return sb.toString();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean usingTimestamp() {
        return usingTimestamp;
    }

}
