/**
 * 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.api.dml.scan;

import com.akiban.server.rowdata.RowData;
import com.akiban.server.rowdata.RowDataExtractor;
import com.akiban.server.rowdata.RowDef;
import com.akiban.server.api.dml.ColumnSelector;
import com.akiban.server.api.dml.DMLError;
import com.akiban.server.service.session.Session;
import com.akiban.server.store.Store;

import java.util.Map;

public final class LegacyRowWrapper extends NewRow
{
    // Updates are handled by creating a NiceRow from the RowData and applying updates to the NiceRow.
    // When this happens, rowData is set to null, and is regenerated lazily. If newRow is null, then
    // rowData is current.
    private RowData rowData;
    private NiceRow niceRow;

    // For when a LegacyRowWrapper is being reused, e.g. WriteRowRequest.
    public LegacyRowWrapper()
    {
        this((RowDef) null);
    }

    public LegacyRowWrapper(RowDef rowDef)
    {
        super(rowDef);
        setRowData(null);
    }

    public LegacyRowWrapper(RowDef rowDef, RowData rowData)
    {
        super(rowDef);
        setRowData(rowData);
    }

    public LegacyRowWrapper(Session session, RowData rowData, Store store)
    {
        this(rowDef(session, rowData.getRowDefId(), store));
        setRowData(rowData);
    }

    public void setRowData(RowData rowData)
    {
        assert
            rowData == null || rowDef == null || rowData.getRowDefId() == rowDef.getRowDefId()
            : String.format("rowData: %s, rowDef: %s", rowData, rowDef);
        this.rowData = rowData;
        this.niceRow = null;
        this.extractor = null;
    }

    @Override
    public Object put(int index, Object object)
    {
        return niceRow().put(index, object);
    }

    @Override
    public int getTableId()
    {
        assert rowData != null || niceRow != null;
        return niceRow != null ? niceRow.getTableId() : rowData.getRowDefId();
    }

    @Override
    public Object get(int columnId)
    {
        Object object;
        if (rowData == null && niceRow == null) {
            throw new DMLError("Row state has not been set");
        } else {
            object =
                niceRow != null
                ? niceRow.get(columnId)
                : extractor().get(rowDef.getFieldDef(columnId));
        }
        return object;
    }

    @Override
    public boolean hasValue(int columnId)
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public Object remove(int columnId)
    {
        throw new UnsupportedOperationException();
    }

    @Override
    public Map<Integer, Object> getFields()
    {
        return niceRow().getFields();
    }

    @Override
    public RowData toRowData()
    {
        if (rowData == null && niceRow != null) {
            rowData = niceRow.toRowData();
            extractor = null;
            niceRow = null;
        }
        return rowData;
    }

    @Override
    public ColumnSelector getActiveColumns() {
        return niceRow().getActiveColumns();
    }

    @Override
    public boolean isColumnNull(int columnId) {
        return toRowData().isNull(columnId);
    }

    @Override
    public boolean equals(Object o)
    {
        boolean eq;
        if (o == null) {
            eq = false;
        } else if (this == o) {
            eq = true;
        } else if (o instanceof LegacyRowWrapper) {
            LegacyRowWrapper that = (LegacyRowWrapper) o;
            eq = this.niceRow().equals(that.niceRow());
        } else if (o instanceof NiceRow) {
            NiceRow that = (NiceRow) o;
            eq = this.niceRow().equals(that);
        } else {
            eq = false;
        }
        return eq;
    }

    @Override
    public int hashCode()
    {
        return niceRow().hashCode();
    }

    @Override
    public String toString()
    {
        // newRow().toString() would be simpler, but there's a side-effect: If rowData != null, then
        // the rowData is converted to a NiceRow and rowData is set to null.
        return
            rowData == null && niceRow == null ? "null" :
            rowData == null ? niceRow.toString() :
            rowData.toString(rowDef);
    }

    public NiceRow niceRow()
    {
        if (niceRow == null) {
            niceRow = (NiceRow) NiceRow.fromRowData(rowData, rowDef);
            rowData = null;
            extractor = null;
        }
        return niceRow;
    }

    // Allows a LegacyRowWrapper to be used for a RowData acting as a container of rows of any type.
    public void setRowDef(RowDef rowDef)
    {
        this.rowDef = rowDef;
        niceRow = null;
    }

    private RowDataExtractor extractor()
    {
        if (extractor == null) {
            extractor = new RowDataExtractor(rowData, rowDef);
        }
        return extractor;
    }

    private RowDataExtractor extractor;
}

@@ -2076,16 +2076,13 @@
 his(
-(RowDef)
+null,
  nul
@@ -2153,42 +2153,21 @@
     
-super
+this
 (rowDef
-);%0A        setRowData(
+, 
 null
@@ -2204,29 +2204,31 @@
 Wrapper(
-RowDef rowDef
+Session session
 , RowDat
@@ -2228,32 +2228,45 @@
  RowData rowData
+, Store store
 )%0A    %7B%0A        
@@ -2269,42 +2269,60 @@
     
-super
+this
 (rowDef
-);%0A        setRowData(
+(session, rowData.getRowDefId(), store), 
 rowD
@@ -2358,39 +2358,37 @@
 yRowWrapper(
-Session session
+RowDef rowDef
 , RowData ro
@@ -2388,37 +2388,24 @@
 Data rowData
-, Store store
 )%0A    %7B%0A    
@@ -2412,58 +2412,20 @@
     
-this(rowDef(session, rowData.getRowDefId(), store)
+super(rowDef
 );%0A 

Clean up LegacyRowWrapper constructor delegation