/*
 * Copyright 2014 Blazebit.
 *
 * 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 com.blazebit.persistence;

import static com.googlecode.catchexception.CatchException.verifyException;
import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import org.junit.experimental.categories.Category;

import com.blazebit.persistence.entity.Document;
import com.blazebit.persistence.testsuite.base.category.NoHibernate;

/**
 *
 * @author Christian Beikov
 * @author Moritz Becker
 * @since 1.0
 */
public class InTest extends AbstractCoreTest {

    // TODO: Enable again when HHH-7407 is fixed
    @Test
    @Category({ NoHibernate.class })
    public void testBuggyHqlIn() {
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        List<Integer> indicies = Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5 });
        criteria
            .where("1").eqExpression("1")
            .whereOr()
                .where("1").eqExpression("1")
                .where("d.idx").in(indicies)
            .endOr();

        assertEquals("SELECT d FROM Document d WHERE 1 = 1 AND (1 = 1 OR d.idx IN :param_0)", criteria.getQueryString());
        criteria.getResultList();
    }

    // TODO: Enable again when HHH-7407 is fixed
    @Test
    @Category({ NoHibernate.class })
    public void testBuggyHqlIn1() {
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        List<Integer> indicies = Arrays.asList(new Integer[]{ 1, 2, 3, 4, 5 });
        criteria
            .whereOr()
                .where("1").eqExpression("1")
                .whereAnd()
                    .where("1").eqExpression("1")
                    .where("d.idx").in(indicies)
                .endAnd()
            .endOr();

        assertEquals("SELECT d FROM Document d WHERE 1 = 1 OR (1 = 1 AND d.idx IN :param_0)", criteria.getQueryString());
        criteria.getResultList();
    }
    
    @Test
    public void testIn() {
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        List<Long> ages = new ArrayList<Long>(Arrays.asList(new Long[]{ 1L, 2L, 3L, 4L, 5L }));
        criteria.where("d.age").in(ages);

        assertEquals("SELECT d FROM Document d WHERE d.age IN " + listParameter("param_0"), criteria.getQueryString());
        criteria.getResultList();
    }

    @Test
    public void testInNull() {
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        verifyException(criteria.where("d.age"), NullPointerException.class).in((List<?>) null);
    }

    @Test
    public void testNotIn() {
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        List<Long> ages = new ArrayList<Long>(Arrays.asList(new Long[]{ 1L, 2L, 3L, 4L, 5L }));
        criteria.where("d.age").notIn(ages);
        assertEquals("SELECT d FROM Document d WHERE d.age NOT IN " + listParameter("param_0"), criteria.getQueryString());
        criteria.getResultList();
    }

    @Test
    public void testNotInNull() {
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        verifyException(criteria.where("d.age"), NullPointerException.class).notIn((List<?>) null);
    }
    
    @Test
    public void testInSubqueryAliasExpression1(){
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        criteria.where("d.id").nonPortable()
                .in("alias", "(FUNCTION('zero', alias, :elementCount))")
                    .from(Document.class, "d2")
                    .select("d2.id")
                    .select("FUNCTION('zero',FUNCTION('zero',d2.id,FUNCTION('zero',FUNCTION('zero',:colors))),1)", "colorMatches")
                .end();
        assertEquals("SELECT d FROM Document d WHERE d.id IN (" + function("zero", "(SELECT d2.id, " + function("zero", function("zero", "d2.id", function("zero", function("zero", ":colors"))), "1") + " AS colorMatches FROM Document d2)", ":elementCount") + ")", criteria.getQueryString());
    }
    
    // this is not redundant with testInSubqueryAliasExpression1o
    @Test
    public void testInSubqueryAliasExpression2(){
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d");
        criteria.where("d.id").nonPortable()
                .in("alias", "(FUNCTION('zero', alias, :elementCount))")
                    .from(Document.class, "d2")
                .end();
        assertEquals("SELECT d FROM Document d WHERE d.id IN (" + function("zero", "(SELECT d2 FROM Document d2)", ":elementCount") + ")", criteria.getQueryString());
    }
    
    @Test
    public void testInEmptyListConditional(){
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d")
            .where("d.id").in(new ArrayList<Object>());
        assertEquals("SELECT d FROM Document d WHERE " + booleanConditionalExpression(false), criteria.getQueryString());
    }
    
    @Test
    public void testNotInEmptyListConditional(){
        CriteriaBuilder<Document> criteria = cbf.create(em, Document.class, "d")
            .where("d.id").notIn(new ArrayList<Object>());
        assertEquals("SELECT d FROM Document d WHERE " + booleanConditionalExpression(true), criteria.getQueryString());
    }
}

@@ -1708,32 +1708,56 @@
 OR d.idx IN 
-:
+%22 + listParameter(%22
 param_0
+%22) + %22
 )%22, criteria
@@ -2459,16 +2459,40 @@
  IN 
-:
+%22 + listParameter(%22
 param_0
+%22) + %22
 )%22, 

Fix datanucleus problems