/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.shardingsphere.sql.parser.binder.segment.select.pagination.engine;

import org.apache.shardingsphere.sql.parser.binder.segment.select.pagination.PaginationContext;
import org.apache.shardingsphere.sql.parser.binder.segment.select.projection.ProjectionsContext;
import org.apache.shardingsphere.sql.parser.sql.segment.dml.item.ProjectionsSegment;
import org.apache.shardingsphere.sql.parser.sql.segment.dml.pagination.limit.LimitSegment;
import org.apache.shardingsphere.sql.parser.sql.segment.dml.pagination.limit.NumberLiteralLimitValueSegment;
import org.apache.shardingsphere.sql.parser.sql.segment.dml.pagination.top.TopProjectionSegment;
import org.apache.shardingsphere.sql.parser.sql.segment.dml.predicate.WhereSegment;
import org.apache.shardingsphere.sql.parser.sql.statement.dml.SelectStatement;
import org.junit.Test;

import java.util.Collections;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public final class PaginationContextEngineTest {
    
    @Test
    public void assertCreatePaginationContextWhenLimitSegmentIsPresent() {
        SelectStatement selectStatement = new SelectStatement();
        selectStatement.setLimit(new LimitSegment(0, 10, new NumberLiteralLimitValueSegment(0, 10, 100L),
                new NumberLiteralLimitValueSegment(0, 10, 100L)));
        PaginationContext paginationContext = new PaginationContextEngine().createPaginationContext(selectStatement, null, Collections.emptyList());
        assertTrue(paginationContext.getOffsetSegment().isPresent());
        assertTrue(paginationContext.getRowCountSegment().isPresent());
    }
    
    @Test
    public void assertCreatePaginationContextWhenLimitSegmentAbsentAndTopSegmentPresent() {
        SelectStatement selectStatement = new SelectStatement();
        ProjectionsSegment projections = new ProjectionsSegment(0, 0);
        projections.getProjections().add(new TopProjectionSegment(0, 10, null, "rowNumberAlias"));
        selectStatement.setProjections(projections);
        PaginationContext paginationContext = new PaginationContextEngine().createPaginationContext(selectStatement, null, Collections.emptyList());
        assertFalse(paginationContext.getOffsetSegment().isPresent());
        assertFalse(paginationContext.getRowCountSegment().isPresent());
    }
    
    @Test
    public void assertCreatePaginationContextWhenLimitSegmentTopSegmentAbsentAndWhereSegmentPresent() {
        SelectStatement selectStatement = new SelectStatement();
        selectStatement.setProjections(new ProjectionsSegment(0, 0));
        selectStatement.setWhere(new WhereSegment(0, 10));
        
        ProjectionsContext projectionsContext = new ProjectionsContext(0, 0, false, Collections.emptyList());
        PaginationContext paginationContext = new PaginationContextEngine().createPaginationContext(selectStatement, projectionsContext, Collections.emptyList());
        assertFalse(paginationContext.getOffsetSegment().isPresent());
        assertFalse(paginationContext.getRowCountSegment().isPresent());
    }
    
    @Test
    public void assertCreatePaginationContextWhenResultIsPaginationContext() {
        SelectStatement selectStatement = new SelectStatement();
        selectStatement.setProjections(new ProjectionsSegment(0, 0));
        ProjectionsContext projectionsContext = new ProjectionsContext(0, 0, false, Collections.emptyList());
        assertThat(new PaginationContextEngine().createPaginationContext(selectStatement, projectionsContext, Collections.emptyList()), instanceOf(PaginationContext.class));
    }
}

@@ -1068,32 +1068,286 @@
 ectionsContext;%0A
+import org.apache.shardingsphere.sql.parser.sql.segment.dml.TableFactorSegment;%0Aimport org.apache.shardingsphere.sql.parser.sql.segment.dml.TableReferenceSegment;%0Aimport org.apache.shardingsphere.sql.parser.sql.segment.dml.expr.subquery.SubquerySegment;%0A
 import org.apach
@@ -1407,32 +1407,32 @@
 ectionsSegment;%0A
-
 import org.apach
@@ -1788,32 +1788,124 @@
 e.WhereSegment;%0A
+import org.apache.shardingsphere.sql.parser.sql.segment.generic.table.SubqueryTableSegment;%0A
 import org.apach
@@ -3003,32 +3003,40 @@
 electStatement s
+ubqueryS
 electStatement =
@@ -3230,32 +3230,40 @@
 as%22));%0A        s
+ubqueryS
 electStatement.s
@@ -3290,16 +3290,551 @@
 tions);%0A
+        SubquerySegment subquerySegment = new SubquerySegment(0, 0, subquerySelectStatement);%0A        TableFactorSegment tableFactorSegment = new TableFactorSegment();%0A        tableFactorSegment.setTable(new SubqueryTableSegment(subquerySegment));%0A        TableReferenceSegment tableReferenceSegment = new TableReferenceSegment();%0A        tableReferenceSegment.setTableFactor(tableFactorSegment);%0A        SelectStatement selectStatement = new SelectStatement();%0A        selectStatement.getTableReferences().add(tableReferenceSegment);%0A
         

add top pagination test case