/**
 * END USER LICENSE AGREEMENT (“EULA”)
 *
 * READ THIS AGREEMENT CAREFULLY (date: 9/13/2011):
 * http://www.akiban.com/licensing/20110913
 *
 * BY INSTALLING OR USING ALL OR ANY PORTION OF THE SOFTWARE, YOU ARE ACCEPTING
 * ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. YOU AGREE THAT THIS
 * AGREEMENT IS ENFORCEABLE LIKE ANY WRITTEN AGREEMENT SIGNED BY YOU.
 *
 * IF YOU HAVE PAID A LICENSE FEE FOR USE OF THE SOFTWARE AND DO NOT AGREE TO
 * THESE TERMS, YOU MAY RETURN THE SOFTWARE FOR A FULL REFUND PROVIDED YOU (A) DO
 * NOT USE THE SOFTWARE AND (B) RETURN THE SOFTWARE WITHIN THIRTY (30) DAYS OF
 * YOUR INITIAL PURCHASE.
 *
 * IF YOU WISH TO USE THE SOFTWARE AS AN EMPLOYEE, CONTRACTOR, OR AGENT OF A
 * CORPORATION, PARTNERSHIP OR SIMILAR ENTITY, THEN YOU MUST BE AUTHORIZED TO SIGN
 * FOR AND BIND THE ENTITY IN ORDER TO ACCEPT THE TERMS OF THIS AGREEMENT. THE
 * LICENSES GRANTED UNDER THIS AGREEMENT ARE EXPRESSLY CONDITIONED UPON ACCEPTANCE
 * BY SUCH AUTHORIZED PERSONNEL.
 *
 * IF YOU HAVE ENTERED INTO A SEPARATE WRITTEN LICENSE AGREEMENT WITH AKIBAN FOR
 * USE OF THE SOFTWARE, THE TERMS AND CONDITIONS OF SUCH OTHER AGREEMENT SHALL
 * PREVAIL OVER ANY CONFLICTING TERMS OR CONDITIONS IN THIS AGREEMENT.
 */

package com.akiban.server.types3.common.funcs;

import com.akiban.server.types3.LazyList;
import com.akiban.server.types3.TClass;
import com.akiban.server.types3.TCustomOverloadResult;
import com.akiban.server.types3.TExecutionContext;
import com.akiban.server.types3.TInstance;
import com.akiban.server.types3.TOverload;
import com.akiban.server.types3.TOverloadResult;
import com.akiban.server.types3.TPreptimeContext;
import com.akiban.server.types3.TPreptimeValue;
import com.akiban.server.types3.pvalue.PValueSource;
import com.akiban.server.types3.pvalue.PValueTarget;
import com.akiban.server.types3.texpressions.TInputSetBuilder;
import com.akiban.server.types3.texpressions.TOverloadBase;
import java.util.List;

public abstract class Pad extends TOverloadBase
{
    public static TOverload[] create(TClass stringType, TClass intType)
    {
        return new TOverload[]
        {
            new Pad(stringType, intType, "LPAD") // prepend
            {
                @Override
                String doPadding(String st, int times, String toAdd)
                {
                    StringBuilder prefix = new StringBuilder();
                    
                    while (times-- >= 0)
                        prefix.append(toAdd);
                    
                    return prefix.append(st).toString();
                }   
            },
            new Pad(stringType, intType, "RPAD") // append
            {
                @Override
                String doPadding(String st, int times, String toAdd)
                {
                    StringBuilder ret = new StringBuilder(st);
                    while (times-- >= 0)
                        ret.append(toAdd);
                    return ret.toString();
                }
            }
        };
    }

    abstract String doPadding(String st, int times, String toAdd);
    
    private final TClass stringType;
    private final TClass intType;
    private final String name;
    
    Pad(TClass stringType, TClass intType, String name)
    {
        this.stringType = stringType;
        this.intType = intType;
        this.name = name;
    }
    
    @Override
    protected void doEvaluate(TExecutionContext context, LazyList<? extends PValueSource> inputs, PValueTarget output)
    {
        String st = (String) inputs.get(0).getObject();
        int length = inputs.get(1).getInt32();
        String toAdd = (String) inputs.get(2).getObject();
        
        if (length < 0)
            output.putNull();
        else if (length <= st.length())
            output.putObject(st.substring(0, length));
        else if (toAdd.isEmpty())
            output.putNull();
        else
            output.putObject(doPadding(st, length, toAdd));
    }
    
    @Override
    protected void buildInputSets(TInputSetBuilder builder)
    {
        builder.covers(stringType, 0, 2).covers(intType, 1);
    }

    @Override
    public String overloadName()
    {
        return name;
    }

    @Override
    public TOverloadResult resultType()
    {
        return TOverloadResult.custom(new TCustomOverloadResult()
        {
            @Override
            public TInstance resultInstance(List<TPreptimeValue> inputs, TPreptimeContext context)
            {
                PValueSource len = inputs.get(1).value();
                
                // if the argument isn't availabe or is null
                // return LONGTEXT 
                if (len == null || len.isNull())
                    throw new UnsupportedOperationException("LONGTEXT type is not available");
                else
                    return stringType.instance(len.getInt32());
            }
        });
    }
    
}

@@ -2368,16 +2368,36 @@
 ilder();
+                    
 %0A       
@@ -2401,32 +2401,178 @@
                 
+int delta = times - st.length();%0A                    int limit = delta / toAdd.length();%0A                    int remain = delta %25 toAdd.length();%0A
 %0A               
@@ -2579,34 +2579,33 @@
      while (
-times
+limit
 -- %3E
-=
  0)%0A        
@@ -2631,32 +2631,141 @@
 fix.append(toAdd
+);%0A                    for (int n = 0; n %3C remain; ++n)%0A                        prefix.append(toAdd.charAt(n)
 );%0A             
@@ -3114,16 +3114,203 @@
 er(st);%0A
+                    int delta = times - st.length();%0A                    int limit = delta / toAdd.length();%0A                    int remain = delta %25 toAdd.length();%0A                    %0A
         
@@ -3332,18 +3332,17 @@
 le (
-times
+limit
 -- %3E
-=
  0)%0A
@@ -3376,32 +3376,139 @@
 .append(toAdd);%0A
+                    for (int n = 0; n %3C remain; ++n)%0A                        ret.append(toAdd.charAt(n));%0A%0A
                 
@@ -5167,20 +5167,9 @@
 labe
- or is null
 %0A
+
     
@@ -5235,24 +5235,8 @@
 null
- %7C%7C len.isNull()
 )%0A  
@@ -5328,16 +5328,106 @@
 able%22);%0A
+                else if (len.isNull())%0A                    return stringType.instance(0);%0A
         

address review comments