/**
 *    Copyright 2016-2017 the original author or authors.
 *
 *    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.mybatis.dynamic.sql.select;

import java.util.Arrays;
import java.util.stream.Collectors;

import org.mybatis.dynamic.sql.Condition;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.SqlCriterion;
import org.mybatis.dynamic.sql.SqlTable;
import org.mybatis.dynamic.sql.where.AbstractWhereBuilder;
import org.mybatis.dynamic.sql.where.WhereSupport;

public class SelectSupportBuilder {

    private SelectSupport.Builder builder = new SelectSupport.Builder();

    private SelectSupportBuilder() {
        super();
    }
    
    private SelectSupportBuilder(SqlColumn<?>...columns) {
        builder.withColumnList(calculateColumnList(columns));
    }
    
    public SelectSupportAfterFromBuilder from(SqlTable table) {
        builder.withTable(table);
        return new SelectSupportAfterFromBuilder();
    }

    private String calculateColumnList(SqlColumn<?>...columns) {
        return Arrays.stream(columns)
                .map(SqlColumn::nameIncludingTableAndColumnAlias)
                .collect(Collectors.joining(", ")); //$NON-NLS-1$
    }

    public static SelectSupportBuilder of(SqlColumn<?>...columns) {
        return new SelectSupportBuilder(columns);
    }
    
    public static SelectSupportBuilder ofDistinct(SqlColumn<?>...columns) {
        SelectSupportBuilder builder = SelectSupportBuilder.of(columns);
        builder.builder.isDistinct();
        return builder;
    }
    
    public static SelectSupportBuilder forCount() {
        SelectSupportBuilder builder = new SelectSupportBuilder();
        builder.builder.withColumnList("count(*)"); //$NON-NLS-1$
        return builder;
    }
    
    public class SelectSupportAfterFromBuilder {
        private SelectSupportAfterFromBuilder() {
            super();
        }
        
        public <T> SelectSupportWhereBuilder where(SqlColumn<T> column, Condition<T> condition, SqlCriterion<?>...subCriteria) {
            return new SelectSupportWhereBuilder(column, condition, subCriteria);
        }

        public SelectSupportAfterOrderByBuilder orderBy(SqlColumn<?>...columns) {
            String orderByClause = 
                    Arrays.stream(columns)
                    .map(SqlColumn::orderByPhrase)
                    .collect(Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            builder.withOrderByClause(orderByClause);
            return new SelectSupportAfterOrderByBuilder();
        }
        
        public SelectSupport build() {
            return builder.build();
        }
    }
    
    public class SelectSupportWhereBuilder extends AbstractWhereBuilder<SelectSupportWhereBuilder> {
        private <T> SelectSupportWhereBuilder(SqlColumn<T> column, Condition<T> condition, SqlCriterion<?>...subCriteria) {
            super(column, condition, subCriteria);
        }
        
        public SelectSupportAfterOrderByBuilder orderBy(SqlColumn<?>...columns) {
            String orderByClause = 
                    Arrays.stream(columns)
                    .map(SqlColumn::orderByPhrase)
                    .collect(Collectors.joining(", ", "order by ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
            buildWhereSupport();
            builder.withOrderByClause(orderByClause);
            return new SelectSupportAfterOrderByBuilder();
        }
        
        public SelectSupport build() {
            buildWhereSupport();
            return builder.build();
        }
        
        private void buildWhereSupport() {
            WhereSupport whereSupport = renderCriteria(SqlColumn::nameIncludingTableAlias);
            builder.withParameters(whereSupport.getParameters())
                .withWhereClause(whereSupport.getWhereClause());
        }

        @Override
        protected SelectSupportWhereBuilder getThis() {
            return this;
        }
    }
    
    public class SelectSupportAfterOrderByBuilder {
        private SelectSupportAfterOrderByBuilder() {
            super();
        }
        
        public SelectSupport build() {
            return builder.build();
        }
    }
}

@@ -1728,24 +1728,299 @@
 NLS-1$%0A    %7D
+%0A    %0A    private String calculateOrderByPhrase(SqlColumn%3C?%3E...columns) %7B%0A        return Arrays.stream(columns)%0A                .map(SqlColumn::orderByPhrase)%0A                .collect(Collectors.joining(%22, %22, %22order by %22, %22%22)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$%0A    %7D
 %0A%0A    public
@@ -3039,292 +3039,65 @@
     
-String orderByClause = %0A                    Arrays.stream(columns)%0A                    .map(SqlColumn::orderByPhrase)%0A                    .collect(Collectors.joining(%22, %22, %22order by %22, %22%22)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$%0A            builder.withOrderByClause(orderByClause
+builder.withOrderByClause(calculateOrderByPhrase(columns)
 );%0A 
@@ -3650,253 +3650,8 @@
 ) %7B%0A
-            String orderByClause = %0A                    Arrays.stream(columns)%0A                    .map(SqlColumn::orderByPhrase)%0A                    .collect(Collectors.joining(%22, %22, %22order by %22, %22%22)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$%0A
     
@@ -3721,21 +3721,39 @@
 use(
-orderByClause
+calculateOrderByPhrase(columns)
 );%0A 

Remove some copy/paste code