package org.drizzle.jdbc;

import java.io.*;
import java.nio.charset.Charset;
import java.sql.Clob;
import java.sql.NClob;
import java.sql.SQLException;

public class DrizzleClob extends DrizzleBlob implements Clob, NClob {

    public String toString() {
      try {
        return new String(blobContent, "UTF-8");
      }
      catch(Exception e) {
          throw new AssertionError(e);
      }
    }

    public DrizzleClob(byte [] bytes) {
        super(bytes);
    }
    public DrizzleClob() {
        super();
    }

    public String getSubString(long pos, int length) throws SQLException {
        try {
            return toString().substring((int) pos - 1, (int) pos - 1 + length);
        }
        catch(Exception e) {
            throw new SQLException(e);
        }
    }

    public Reader getCharacterStream() throws SQLException {
        return new StringReader(toString());
    }

    public InputStream getAsciiStream() throws SQLException {
        return getBinaryStream();
    }

    public long position(String searchstr, long start) throws SQLException {
        return toString().indexOf(searchstr, (int)start -1);
    }

    /**
     * Convert character position into byte position in UTF8 byte array.
     * @param charPosition
     * @return byte position
     */
    private int UTF8position(int charPosition) {
        int pos = 0;
        for(int i = 0; i < charPosition; i++)  {
            int c = blobContent[pos] & 0xff;
            if(c < 0x80) {
                pos += 1;
            }
            else if((c & 0xC0) == 0xC0) {
                pos += 2;
            }
            else if ((c & 0xE0) == 0xE0) {
                pos += 3;
            }
            else if ((c & 0xF0) == 0xF0) {
                pos += 4;
            }
            else {
                throw new AssertionError("invalid UTF8");
            }
        }
        return pos;
    }

    public long position(Clob searchstr, long start) throws SQLException {
        return position(searchstr.toString(), start);
    }

    public int setString(long pos, String str) throws SQLException {
        int bytePosition = UTF8position((int)pos-1);
        super.setBytes(bytePosition+1, str.getBytes(Charset.forName("UTF-8")));
        return str.length();
    }

    public int setString(long pos, String str, int offset, int len) throws SQLException {
        return setString(pos, str.substring(offset, offset+len));
    }

    public OutputStream setAsciiStream(long pos) throws SQLException {
       return setBinaryStream(UTF8position((int)pos-1)+1);
    }

    public Writer setCharacterStream(long pos) throws SQLException {
        int bytePosition  = UTF8position((int)pos-1);
        OutputStream stream = setBinaryStream(bytePosition+1);
        return new OutputStreamWriter(stream, Charset.forName("UTF-8"));
    }


    public Reader getCharacterStream(long pos, long length) throws SQLException {
       String s = toString();
       String sub = toString().substring((int)pos -1, (int)pos -1 + (int)length);
       return new StringReader(sub);
    }
}

@@ -3177,12 +3177,732 @@
 %0D%0A    %7D%0D
+%0A%0D%0A    @Override%0D%0A    /**%0D%0A     * return character length of the Clob. Assume UTF8 encoding.%0D%0A     */%0D%0A    public long length() %7B%0D%0A       long len = 0;%0D%0A       for(int i = 0; i %3C blobContent.length;)  %7B%0D%0A            int c = blobContent%5Bpos%5D & 0xff;%0D%0A            if(c %3C 0x80) %7B%0D%0A                i += 1;%0D%0A            %7D%0D%0A            else if((c & 0xC0) == 0xC0) %7B%0D%0A                i += 2;%0D%0A            %7D%0D%0A            else if ((c & 0xE0) == 0xE0) %7B%0D%0A                i += 3;%0D%0A            %7D%0D%0A            else if ((c & 0xF0) == 0xF0) %7B%0D%0A                i += 4;%0D%0A            %7D%0D%0A            else %7B%0D%0A                throw new AssertionError(%22invalid UTF8%22);%0D%0A            %7D%0D%0A           len++;%0D%0A        %7D%0D%0A        return len;%0D%0A    %7D%0D
 %0A%7D%0D%0A

fix Clob length calculation (should be character length)