package com.utopiaindustries.querybuilder;

import com.utopiaindustries.util.MySQLUtils;
import com.utopiaindustries.util.StringUtils;

public class QueryBuilder {
    private StringBuilder query;
    private String table;
    private boolean previousCondition;

    public QueryBuilder() {
        this.query = new StringBuilder();
        this.previousCondition = false;
    }

    // setTable
    public QueryBuilder setTable( String table ) {
        this.table = table;
        return this;
    }

    // selectColumns
    public QueryBuilder setColumns( String[] columns ) {
        String formattedColumns = formatColumns( columns );
        this.query.append( String.format( "SELECT %s FROM %s", formattedColumns, this.table ) );
        this.query.append( " " );
        return this;
    }

    public QueryBuilder setColumnsWithoutFormat( String[] columns ) {
        this.query.append( String.format( "SELECT %s FROM %s", String.join( ",", columns ), this.table ) );
        this.query.append( " " );
        return this;
    }

    // selectColumns
    public QueryBuilder setJoinColumns( String[] columns ) {
        String formattedColumns = formatJoinColumns( columns );
        this.query.append( String.format( "SELECT %s FROM %s", formattedColumns, this.table ) );
        this.query.append( " " );
        return this;
    }

    public QueryBuilder setColumns( String column ) {
        String formattedColumn = column.equals( "*" ) ? "*" : String.format( "`%s`", column );
        this.query.append( String.format( "SELECT %s FROM %s", formattedColumn, this.table ) );
        this.query.append( " " );
        return this;
    }

    // set columns without formatting
    public QueryBuilder setColumnsWithoutFormat( String columns ) {
        this.query.append( String.format( "SELECT %s FROM %s", columns, this.table ) );
        this.query.append( " " );
        return this;
    }

    // set column for count
    public QueryBuilder setColumnForCount( String column ) {
        String formattedColumn = column.equals( "*" ) ? "*" : String.format( "`%s`", column );
        this.query.append( String.format( "SELECT COUNT( %s ) FROM %s", formattedColumn, this.table ) );
        this.query.append( " " );
        return this;
    }

    // where
    public QueryBuilder where() {
        this.query.append( "WHERE" );
        this.query.append( " " );
        return this;
    }


    // columns are Equal
    public QueryBuilder columnsAreEqual( String col1, String col2 ) {
        this.query.append( String.format( "`%s` = `%s`", col1, col2 ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }

    // columnEquals
    public QueryBuilder columnEquals( String col, Integer val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` = %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEquals( String col, Long val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` = %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEquals( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` = \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEqualsWithoutBackTicks( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "%s = \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnJoinEquals( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            String[] parts = col.split( "\\." );
            this.query.append( String.format( "`%s`.`%s` = \"%s\"", parts[0], parts[1], MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEquals( String col, Boolean val ) {
        if ( isNotNull( val ) ) {
            this.query.append( String.format( "`%s` = %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnDateEquals( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` = '%s'", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnJoinDateEquals( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            String[] parts = col.split( "\\." );
            this.query.append( String.format( "`%s`.`%s` = %s", parts[0], parts[1], MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnNotEquals
    public QueryBuilder columnNotEquals( String col, Long val ) {
        if ( val != null ) {
            this.query.append( String.format( "%s != %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnNotEquals
    public QueryBuilder columnNotEquals( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` != \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnEqualsAnd
    public QueryBuilder columnEqualsAnd( String col, String[] vals ) {
        int index = 1;
        for ( String val : vals ) {
            if ( index == 1 ) {
                this.query.append( "(" );
            }
            this.query.append( String.format( "`%s` = \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            if ( index != vals.length ) {
                this.query.append( " " );
                this.query.append( "AND" );
                this.query.append( " " );
            }
            if ( index == vals.length ) {
                this.query.append( ")" );
            }
            index++;
        }
        return this;
    }

    // columnEqualsOr
    public QueryBuilder columnEqualsOr( String col, String[] vals ) {
        int index = 1;
        for ( String val : vals ) {
            if ( index == 1 ) {
                this.query.append( "(" );
            }
            this.query.append( String.format( "`%s` = \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            if ( index != vals.length ) {
                this.query.append( " " );
                this.query.append( "OR" );
                this.query.append( " " );
            }
            if ( index == vals.length ) {
                this.query.append( ")" );
            }
            index++;
        }
        return this;
    }

    // columnGreaterThan
    public QueryBuilder columnGreaterThan( String col, Integer val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` > %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnGreaterThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` > %s", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnEqualToOrGreaterThan
    public QueryBuilder columnEqualToOrGreaterThan( String col, Integer val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` >= %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEqualToOrGreaterThan( String col, Long val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` >= %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEqualToOrGreaterThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` >= %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnDateEqualToOrGreaterThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` >= '%s'", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnDateGreaterThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` > '%s'", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnDateWthoutBackTicksEqualToOrGreaterThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "%s >= '%s'", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnJoinDateEqualToOrGreaterThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            String[] parts = col.split( "\\." );
            this.query.append( String.format( "`%s`.`%s` >= '%s'", parts[0], parts[1], MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnLessThan
    public QueryBuilder columnLessThan( String col, Integer val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` < %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnLessThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` < %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnEqualToOrLessThan
    public QueryBuilder columnEqualToOrLessThan( String col, Integer val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` <= %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEqualToOrLessThan( String col, Long val ) {
        if ( val != null ) {
            this.query.append( String.format( "`%s` <= %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnEqualToOrLessThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` <= %s", col, val ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnDateEqualToOrLessThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` <= '%s'", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnDateLessThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` < '%s'", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnDateWithoutBackTicksEqualToOrLessThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "%s <= '%s'", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnJoinDateEqualToOrLessThan( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            String[] parts = col.split( "\\." );
            this.query.append( String.format( "`%s`.`%s` <= '%s'", parts[0], parts[1], MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnBetween
    public QueryBuilder columnBetween( String col, int val1, int val2 ) {
        this.query.append( String.format( "`%s` BETWEEN %s AND %s", col, val1, val2 ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }

    public QueryBuilder columnBetweenDate( String col, String val1, String val2 ) {
        if ( isNotNullOrEmpty( val1 ) && isNotNullOrEmpty( val2 ) ) {
            this.query.append( String.format( "%s BETWEEN %s AND %s", col, MySQLUtils.escapeString( val1 ), MySQLUtils.escapeString( val2 ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val1 );
        return this;
    }

    public QueryBuilder columnBetween( String col, String val1, String val2 ) {
        if ( isNotNullOrEmpty( val1 ) && isNotNullOrEmpty( val2 ) ) {
            this.query.append( String.format( "%s BETWEEN \"%s\" AND \"%s\"", col, MySQLUtils.escapeString( val1 ), MySQLUtils.escapeString( val2 ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val1 );
        return this;
    }

    // columnLike
    public QueryBuilder columnLike( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` LIKE \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnLikeJoin
    public QueryBuilder columnLikeJoin( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "%s LIKE \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    //for stock report column like join sku
    public QueryBuilder columnLikeSku( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            String modifiedVal = val.replace("'", "%");
            this.query.append( String.format( "%s LIKE '%s'", col, ( modifiedVal ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    //for stock report column like join title
    public QueryBuilder columnLikeTitle(String col, String val) {
        if (isNotNullOrEmpty(val)) {
            String modifiedVal = val.replace("'", "%");
            this.query.append(String.format("`%s` LIKE '%s'", col, modifiedVal));
            this.query.append(" ");
        }
        setPreviousCondition(val);
        return this;
    }

    // columnNotLike
    public QueryBuilder columnNotLike( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "`%s` NOT LIKE \"%s\"", col, MySQLUtils.escapeString( val ) ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // full text search
    public QueryBuilder columnFullText( String[] cols, String val, String operator ) {
        if ( isNotNullOrEmpty( val ) ) {
            // match phrase
            String matchPhrase = String.format( "MATCH (%s) ", String.join( ",", cols ) );
            this.query.append( matchPhrase );
            // against phrase
            String againstPhrase = String.format( "AGAINST ('%s' IN BOOLEAN MODE)", StringUtils.formatAgainstPhraseValues( val, operator ) );
            this.query.append( againstPhrase );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder columnFullText( String[] cols, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            // match phrase
            String matchPhrase = String.format( "MATCH (%s) ", String.join( ",", cols ) );
            this.query.append( matchPhrase );
            // against phrase
            String againstPhrase = String.format( "AGAINST ('%s' IN BOOLEAN MODE)", StringUtils.formatAgainstPhraseValues( val, "+" ) );
            this.query.append( againstPhrase );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    // columnIsNull
    public QueryBuilder columnIsNull( String col ) {
        this.query.append( String.format( "`%s` IS NULL", col ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }

    // columnIsNotNull
    public QueryBuilder columnIsNotNull( String col ) {
        this.query.append( String.format( "`%s` IS NOT NULL", col ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }

    // columnIn
    public QueryBuilder columnIn( String col, String[] val ) {
        if ( val == null || val.length == 0 ) {
            this.previousCondition = false;
            return this;
        }
        String formattedValues = formatInValues( val );
        this.query.append( String.format( "`%s` IN %s", col, formattedValues ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }

    public QueryBuilder columnIn( String col, Long[] val ) {
        if ( val == null || val.length == 0 ) {
            this.previousCondition = false;
            return this;
        }
        String formattedValues = formatInValues( val );
        this.query.append( String.format( "`%s` IN %s", col, formattedValues ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }

    public QueryBuilder columnNotIn( String col, Long[] val ) {
        if ( val == null || val.length == 0 ) {
            this.previousCondition = false;
            return this;
        }
        String formattedValues = formatInValues( val );
        this.query.append( String.format( "`%s` NOT IN %s", col, formattedValues ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }


    // columnIn
    public QueryBuilder columnNotIn( String col, String[] val ) {
        if ( val == null || val.length == 0 ) {
            this.previousCondition = false;
            return this;
        }
        String formattedValues = formatInValues( val );
        this.query.append( String.format( "`%s` NOT IN %s", col, formattedValues ) );
        this.query.append( " " );
        this.previousCondition = true;
        return this;
    }

    // comma separated column contains
    public QueryBuilder commaSeparatedColumnContains( String col, Long val ) {
        if ( val != null ) {
            this.query.append( String.format( "find_in_set( %s , `%s` )", val, col ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }

    public QueryBuilder commaSeparatedColumnContains( String col, String val ) {
        if ( isNotNullOrEmpty( val ) ) {
            this.query.append( String.format( "find_in_set( \"%s\" , `%s` )", MySQLUtils.escapeString( val ), col ) );
            this.query.append( " " );
        }
        setPreviousCondition( val );
        return this;
    }


    // orderBy
    public QueryBuilder orderBy( String col, String sort ) {
        this.query.append( String.format( "ORDER BY `%s` %s", col, sort ) );
        this.query.append( " " );
        return this;
    }

    // orderByJoin
    public QueryBuilder orderByJoin( String col, String sort ) {
        String[] parts = col.split( "\\." );
        this.query.append( String.format( "ORDER BY `%s`.`%s` %s", parts[0], parts[1], sort ) );
        this.query.append( " " );
        return this;
    }


    // orderByCastValue
    public QueryBuilder orderByCastColumn( String col, String dataType, String sort ) {
        this.query.append( String.format( "ORDER BY CAST( `%s` AS %s ) %s", col, dataType, sort ) );
        this.query.append( " " );
        return this;
    }


    // orderBy
    public QueryBuilder orderByColumnCondition( String columnCondition, String sort ) {
        this.query.append( String.format( "ORDER BY %s %s", columnCondition, sort ) );
        this.query.append( " " );
        return this;
    }

    // groupBy
    public QueryBuilder groupBy( String col ) {
        this.query.append( String.format( "GROUP BY `%s`", col ) );
        this.query.append( " " );
        return this;
    }

    // limit
    public QueryBuilder limit( Integer val ) {
        if( val != null ) {
            this.query.append( String.format( "LIMIT %s", val ) );
            this.query.append( " " );
        }
        return this;
    }

    public QueryBuilder limit( Long val ) {
        if ( val != null ) {
            this.query.append( String.format( "LIMIT %s", val ) );
            this.query.append( " " );
        }
        return this;
    }

    // not
    public QueryBuilder not() {
        this.query.append( "NOT" );
        this.query.append( " " );
        return this;
    }

    // and
    public QueryBuilder and() {
        if ( this.previousCondition ) {
            this.query.append( "AND" );
            this.query.append( " " );
        }
        return this;
    }

    // or
    public QueryBuilder or() {
        if ( this.previousCondition ) {
            this.query.append( "OR" );
            this.query.append( " " );
        }
        return this;
    }

    //bracket open
    public QueryBuilder bracketOpen() {
        this.query.append( "(" );
        this.query.append( " " );
        return this;
    }

    // bracket close
    public QueryBuilder bracketClose() {
        this.query.append( ")" );
        this.query.append( " " );
        return this;
    }

    // build
    public String build() {
        String queryStr = this.query.toString().trim();
        // check for AND ORDER
        if ( queryStr.contains( " AND ORDER BY " ) ) {
            queryStr = queryStr.replaceAll( " AND ORDER BY ", " ORDER BY " );
        }
        // check for AND LIMIT
        if ( queryStr.contains( " AND LIMIT" ) ) {
            queryStr = queryStr.replaceAll( " AND LIMIT", " LIMIT" );
        }
        // check for AND GROUP BY
        if ( queryStr.contains( " AND GROUP BY" ) ) {
            queryStr = queryStr.replaceAll( " AND GROUP BY", " GROUP BY" );
        }
        // check for ending OR
        if ( queryStr.endsWith( " OR" ) ) {
            queryStr = queryStr.substring( 0, queryStr.lastIndexOf( " OR" ) );
        }
        // check for ending AND
        if ( queryStr.endsWith( " AND" ) ) {
            queryStr = queryStr.substring( 0, queryStr.lastIndexOf( " AND" ) );
        }
        // checking for ending WHERE
        if ( queryStr.endsWith( " WHERE" ) ) {
            queryStr = queryStr.substring( 0, queryStr.lastIndexOf( " WHERE" ) );
        }
        // checking for WHERE ORDER
        if ( queryStr.contains( " WHERE ORDER" ) ) {
            queryStr = queryStr.replaceAll( "WHERE ORDER BY", "ORDER BY" );
        }
        // checking for WHERE LIMIT
        if ( queryStr.contains( " WHERE LIMIT" ) ) {
            queryStr = queryStr.replaceAll( "WHERE LIMIT", "LIMIT" );
        }
        return queryStr;
    }

    // isNotNullOrEmpty
    private boolean isNotNullOrEmpty( String str ) {
        return !( ( str == null ) || str.isEmpty() );
    }

    private boolean isNotNull( Boolean val ) {
        return !( val == null );
    }

    // format columns
    private String formatColumns( String[] columns ) {
        StringBuilder stringBuilder = new StringBuilder();
        for ( String column : columns ) {
            stringBuilder.append( String.format( "`%s`,", column ) );
        }
        String str = stringBuilder.toString();
        if ( str.endsWith( "," ) ) {
            str = str.substring( 0, str.lastIndexOf( "," ) );
        }
        return str;
    }

    // format columns
    private String formatJoinColumns( String[] columns ) {
        StringBuilder stringBuilder = new StringBuilder();
        for ( String column : columns ) {
            int intIndex = column.indexOf( "(" );
            if ( intIndex != -1 ) {
                String[] partsRound = column.split( "\\(" );
                String result = column.substring( column.indexOf( "(" ) + 1, column.indexOf( ")" ) );
                String[] partsPoint = result.split( "\\." );
                System.out.println( result );
                stringBuilder.append( String.format( "%s(", partsRound[0] ) );
                stringBuilder.append( String.format( "`%s`.", partsPoint[0] ) );
                stringBuilder.append( String.format( "`%s`),", partsPoint[1] ) );
            } else {
                String[] parts = column.split( "\\." );
                stringBuilder.append( String.format( "`%s`.", parts[0] ) );
                stringBuilder.append( String.format( "`%s`,", parts[1] ) );
            }

        }
        String str = stringBuilder.toString();
        if ( str.endsWith( "," ) ) {
            str = str.substring( 0, str.lastIndexOf( "," ) );
        }
        return str;
    }

    // format in values
    private String formatInValues( String[] vals ) {
        if ( vals.length == 0 ) {
            return "(\"\")";
        }
        StringBuilder strBuilder = new StringBuilder();
        strBuilder.append( "(" );
        for ( String val : vals ) {
            strBuilder.append( String.format( "\"%s\",", MySQLUtils.escapeString( val ) ) );
        }
        strBuilder.append( ")" );
        String str = strBuilder.toString();
        // check for ending comma
        if ( str.endsWith( ",)" ) ) {
            str = str.substring( 0, str.lastIndexOf( ",)" ) );
            str += ")";
        }
        return str;
    }

    private String formatInValues( Long[] vals ) {
        if ( vals.length == 0 ) {
            return "(\"\")";
        }
        StringBuilder strBuilder = new StringBuilder();
        strBuilder.append( "(" );
        for ( long val : vals ) {
            strBuilder.append( String.format( "%s,", val ) );
        }
        strBuilder.append( ")" );
        String str = strBuilder.toString();
        // check for ending comma
        if ( str.endsWith( ",)" ) ) {
            str = str.substring( 0, str.lastIndexOf( ",)" ) );
            str += ")";
        }
        return str;
    }

    public QueryBuilder setInnerJoin( String table, String columnLeft, String columnRight ) {
        this.query.append( " INNER JOIN " ).append( table ).append( " ON " ).append( columnLeft ).append( " = " ).append( columnRight ).append( " " );
        return this;
    }

    public QueryBuilder setLeftJoin( String table, String columnLeft, String columnRight ) {
        this.query.append( " LEFT JOIN " ).append( table ).append( " ON " ).append( columnLeft ).append( " = " ).append( columnRight ).append( " " );
        return this;
    }

    // set previous condition
    private void setPreviousCondition( String val ) {
        this.previousCondition = isNotNullOrEmpty( val );
    }

    private void setPreviousCondition( Long val ) {
        this.previousCondition = ( val != null );
    }

    private void setPreviousCondition( Integer val ) {
        this.previousCondition = ( val != null );
    }

    private void setPreviousCondition( Boolean val ) {
        this.previousCondition = isNotNull( val );
    }
    public QueryBuilder append(String sqlFragment) {
        this.query.append(sqlFragment);
        return this;
    }
}
