/*
 *  Copyright (c) 2017 Otávio Santana and others
 *   All rights reserved. This program and the accompanying materials
 *   are made available under the terms of the Eclipse Public License v1.0
 *   and Apache License v2.0 which accompanies this distribution.
 *   The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 *   and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
 *
 *   You may elect to redistribute this code under either of these licenses.
 *
 *   Contributors:
 *
 *   Otavio Santana
 *   Lucas Furlaneto
 */
package org.jnosql.diana.orientdb.document;


import org.jnosql.diana.api.TypeReference;
import org.jnosql.diana.api.document.Document;
import org.jnosql.diana.api.document.DocumentCondition;
import org.jnosql.diana.api.document.DocumentQuery;

import java.util.List;

final class QueryOSQLConverter {

    private QueryOSQLConverter() {
    }

    static Query select(DocumentQuery documentQuery) {
        StringBuilder query = new StringBuilder();
        List<Object> params = new java.util.ArrayList<>();
        query.append("SELECT FROM ");
        query.append(documentQuery.getDocumentCollection());
        if (documentQuery.getCondition().isPresent()) {
            query.append(" WHERE ");
            definesCondition(documentQuery.getCondition().get(), query, params, 0);
        }
        return new Query(query.toString(), params);
    }

    private static void definesCondition(DocumentCondition condition, StringBuilder query, List<Object> params, int counter) {
        Document document = condition.getDocument();
        switch (condition.getCondition()) {
            case IN:
                appendCondition(query, params, document, " IN ");
                return;
            case EQUALS:
                appendCondition(query, params, document, " = ");
                return;
            case GREATER_EQUALS_THAN:
                appendCondition(query, params, document, " >= ");
                return;
            case GREATER_THAN:
                appendCondition(query, params, document, " > ");
                return;
            case LESSER_THAN:
                appendCondition(query, params, document, " < ");
                return;
            case LESSER_EQUALS_THAN:
                appendCondition(query, params, document, " <= ");
                return;
            case LIKE:
                appendCondition(query, params, document, " LIKE ");
                return;
            case AND:
                for (DocumentCondition dc : document.get(new TypeReference<List<DocumentCondition>>() {
                })) {

                    if (isFirstCondition(query, counter)) {
                        query.append(" AND ");
                    }
                    definesCondition(dc, query, params, ++counter);
                }
                return;
            case OR:
                for (DocumentCondition dc : document.get(new TypeReference<List<DocumentCondition>>() {
                })) {
                    if (isFirstCondition(query, counter)) {
                        query.append(" OR ");
                    }
                    definesCondition(dc, query, params, ++counter);
                }
                return;
            case NOT:
                DocumentCondition documentCondition = document.get(DocumentCondition.class);
                query.append("NOT (");
                definesCondition(documentCondition, query, params, ++counter);
                query.append(")");
                return;
            default:
                throw new IllegalArgumentException("Orient DB has not support to the condition " + condition.getCondition());
        }
    }

    private static boolean isFirstCondition(StringBuilder query, int counter) {
        return counter > 0 && !" WHERE ".equals(query.substring(query.length() - 7));
    }

    private static void appendCondition(StringBuilder query, List<Object> params, Document document, String condition) {
        query.append(document.getName())
                .append(condition).append("?");
        params.add(document.get());
    }

    static class Query {
        private final String query;
        private final List<Object> params;

        Query(String query, List<Object> params) {
            this.query = query;
            this.params = params;
        }

        String getQuery() {
            return query;
        }

        List<Object> getParams() {
            return params;
        }
    }
}

@@ -894,24 +894,592 @@
 onverter %7B%0A%0A
+    private static final String WHERE = %22 WHERE %22;%0A    private static final String IN = %22 IN %22;%0A    private static final String AND = %22 AND %22;%0A    private static final String OR = %22 OR %22;%0A    private static final String EQUALS = %22 = %22;%0A    private static final String GREATER_EQUALS_THAN = %22 %3E= %22;%0A    private static final String GREATER_THAN = %22 %3E %22;%0A    private static final String LESSER_THAN = %22 %3C %22;%0A    private static final String LESSER_EQUALS_THAN = %22 %3C= %22;%0A    private static final String LIKE = %22 LIKE %22;%0A    private static final char PARAM_APPENDER = '?';%0A%0A
     private 
@@ -1853,25 +1853,21 @@
 .append(
-%22 
 WHERE
- %22
 );%0A     
@@ -2316,22 +2316,18 @@
 cument, 
-%22 IN %22
+IN
 );%0A     
@@ -2427,21 +2427,22 @@
 cument, 
-%22 = %22
+EQUALS
 );%0A     
@@ -2555,22 +2555,35 @@
 cument, 
-%22 %3E= %22
+GREATER_EQUALS_THAN
 );%0A     
@@ -2689,21 +2689,28 @@
 cument, 
-%22 %3E %22
+GREATER_THAN
 );%0A     
@@ -2815,21 +2815,27 @@
 cument, 
-%22 %3C %22
+LESSER_THAN
 );%0A     
@@ -2947,22 +2947,34 @@
 cument, 
-%22 %3C= %22
+LESSER_EQUALS_THAN
 );%0A     
@@ -3071,25 +3071,21 @@
 ocument,
- %22
  LIKE
- %22
 );%0A     
@@ -3349,23 +3349,19 @@
 .append(
-%22 
 AND
- %22
 );%0A     
@@ -3731,22 +3731,18 @@
 .append(
-%22 OR %22
+OR
 );%0A     
@@ -4435,25 +4435,21 @@
 %3E 0 && !
-%22 
 WHERE
- %22
 .equals(
@@ -4701,11 +4701,22 @@
 end(
-%22?%22
+PARAM_APPENDER
 );%0A 

Add string as a const