/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (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.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * 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 com.queplix.core.modules.eql;

import com.queplix.core.error.GenericSystemException;

import java.util.Date;

/**
 * EQL Response Cell object.
 *
 * @author Baranov Andrey [ALB]
 * @version $Revision: 1.2 $ $Date: 2006/01/31 14:39:01 $
 */

public class EQLResCell
        implements java.io.Serializable {

    // ================================================================== Fields

    private EQLReqField reqField;
    private EQLObject eqlObj;
    private EQLObject oldEqlObj;

    private boolean changed = false;
    private boolean isNull = false;

    private EQLResCell listFieldCell;

    // ============================================================ Constructors

    public EQLResCell(EQLReqField reqField, EQLObject eqlObj) {
        if(reqField == null || eqlObj == null) {
            throw new NullPointerException();
        }

        this.reqField = reqField;
        _setEQLObject(eqlObj);
    }

    public EQLResCell(EQLReqField reqField, boolean isNull) {
        this(reqField, EQLNullObject.getInstance());
        this.isNull = isNull;
    }

    // ========================================================== Public methods

    public void addListField(EQLResCell listFieldCell) {
        this.listFieldCell = listFieldCell;
    }

    public EQLReqField getReqField() {
        return reqField;
    }

    public EQLObject getEQLObject() {
        return eqlObj;
    }

    public EQLObject getOldEQLObject() {
        if(oldEqlObj == null) {
            return eqlObj;
        } else {
            return oldEqlObj;
        }
    }

    public synchronized void setEQLObject(EQLObject newO) {

        boolean equals = eqlObj.equals(newO);

        if(!equals) {
            changed = true;
        }

        if(oldEqlObj == null) {
            // remember old object only first time
            oldEqlObj = eqlObj;
        }

        if(!equals) {
            // set new object
            _setEQLObject(newO);
        }
    }

    public void forceNotChanged() {
        this.changed = false;
    }

    public void forceChanged() {
        this.changed = true;
    }

    public boolean isValueChanged() {
        return changed;
    }

    public boolean isNull() {
        return isNull;
    }

    public EQLResCell getListField() {
        return listFieldCell;
    }

    public int hashCode() {
        return reqField.hashCode() | eqlObj.hashCode();
    }

    public boolean equals(Object o) {
        if(o == null || !(o instanceof EQLResCell)) {
            return false;
        }

        if(o == this) {
            return true;
        }

        EQLResCell obj = (EQLResCell) o;
        return reqField.equals(obj.reqField)
                && eqlObj.equals(obj.eqlObj)
                && ((oldEqlObj == null && obj.oldEqlObj == null)
                || (oldEqlObj != null && obj.oldEqlObj != null &&
                oldEqlObj.equals(obj.oldEqlObj)));
    }

    // ========================================================== Access methods

    /**
     * Get cell value
     *
     * @param toClass bind value to class
     * @return cell value
     */
    public Object getObject(Class toClass) {
        return getObject(getEQLObject(), toClass);
    }

    /**
     * Get cell value as string
     *
     * @return cell value
     */
    public String getString() {
        return getString(getEQLObject());
    }

    /**
     * Get cell value as number
     *
     * @return cell value
     */
    public Number getNumber() {
        return getNumber(getEQLObject());
    }

    /**
     * Get cell value as integer
     *
     * @return cell value
     */
    public Integer getInteger() {
        return getInteger(getEQLObject());
    }

    /**
     * Get cell value as long
     *
     * @return cell value
     */
    public Long getLong() {
        return getLong(getEQLObject());
    }

    /**
     * Get cell value as float
     *
     * @return cell value
     */
    public Float getFloat() {
        return getFloat(getEQLObject());
    }

    /**
     * Get cell value as date
     *
     * @return cell value
     */
    public Date getDate() {
        return getDate(getEQLObject());
    }

    /**
     * Get cell value as array of chars
     *
     * @return cell value
     */
    public char[] getMemo() {
        return getMemo(getEQLObject());
    }

    /**
     * Get cell value as array of bytes
     *
     * @return cell value
     */
    public byte[] getBinary() {
        return getBinary(getEQLObject());
    }

    /**
     * Get old cell value
     *
     * @param toClass bind value to class
     * @return old cell value
     */
    public Object getOldObject(Class toClass) {
        return getObject(getOldEQLObject(), toClass);
    }

    /**
     * Get old cell value as string
     *
     * @return old cell value
     */
    public String getOldString() {
        return getString(getOldEQLObject());
    }

    /**
     * Get old cell value as number
     *
     * @return old cell value
     */
    public Number getOldNumber() {
        return getNumber(getOldEQLObject());
    }

    /**
     * Get old cell value as integer
     *
     * @return old cell value
     */
    public Integer getOldInteger() {
        return getInteger(getOldEQLObject());
    }

    /**
     * Get old cell value as long
     *
     * @return old cell value
     */
    public Long getOldLong() {
        return getLong(getOldEQLObject());
    }

    /**
     * Get old cell value as float
     *
     * @return old cell value
     */
    public Float getOldFloat() {
        return getFloat(getOldEQLObject());
    }

    /**
     * Get old cell value as date
     *
     * @return old cell value
     */
    public Date getOldDate() {
        return getDate(getOldEQLObject());
    }

    /**
     * Get old cell value as array of chars
     *
     * @return old cell value
     */
    public char[] getOldMemo() {
        return getMemo(getOldEQLObject());
    }

    /**
     * Get old cell value as array of bytes
     *
     * @return old cell value
     */
    public byte[] getOldBinary() {
        return getBinary(getOldEQLObject());
    }

    /**
     * Set cell value
     *
     * @param o object
     */
    public void setObject(Object o) {
        setEQLObject(EQLObject.getInstance(o));
    }

    /**
     * Set cell value
     *
     * @param s string
     */
    public void setString(String s) {
        setObject(s);
    }

    /**
     * Set cell value
     *
     * @param n number
     */
    public void setNumber(Number n) {
        setObject(n);
    }

    /**
     * Set cell value
     *
     * @param d date
     */
    public void setDate(Date d) {
        setObject(d);
    }

    /**
     * Set cell value
     *
     * @param cs array of chars
     */
    public void setMemo(char[] cs) {
        setObject(cs);
    }

    /**
     * Set cell value
     *
     * @param bs array of bytes
     */
    public void setBinary(byte[] bs) {
        setObject(bs);
    }

    /**
     * Set null
     */
    public void setNull() {
        setObject(null);
    }

    // ========================================================= Public static methods

    /**
     * Get cell value
     *
     * @param o       EQL object
     * @param toClass bind value to class
     * @return cell value
     */
    public static Object getObject(EQLObject o, Class toClass) {

        if(toClass.equals(String.class)) {
            return getString(o);
        } else if(toClass.equals(Integer.class)) {
            return getInteger(o);
        } else if(toClass.equals(Long.class)) {
            return getLong(o);
        } else if(toClass.equals(Float.class)) {
            return getFloat(o);
        } else if(toClass.equals(Number.class)) {
            return getNumber(o);
        } else if(toClass.equals(Date.class)) {
            return getDate(o);
        } else if(toClass.equals(char[].class)) {
            return getMemo(o);
        } else if(toClass.equals(byte[].class)) {
            return getBinary(o);
        } else {
            throw new GenericSystemException(
                    "Unsupported class '" + toClass + "'");
        }
    }

    /**
     * Get cell value as string
     *
     * @param o EQL object
     * @return cell value
     */
    public static String getString(EQLObject o) {
        return (String) o.getObject();
    }

    /**
     * Get cell value as number
     *
     * @param o EQL object
     * @return cell value
     */
    public static Number getNumber(EQLObject o) {
        return (Number) o.getObject();
    }

    /**
     * Get cell value as integer
     *
     * @param o EQL object
     * @return cell value
     */
    public static Integer getInteger(EQLObject o) {
        Number n = getNumber(o);

        if(n == null) {
            return null;
        } else if(n instanceof Integer) {
            return (Integer) n;
        } else {
            return new Integer(n.intValue());
        }
    }

    /**
     * Get cell value as long
     *
     * @param o EQL object
     * @return cell value
     */
    public static Long getLong(EQLObject o) {
        Number n = getNumber(o);

        if(n == null) {
            return null;
        } else if(n instanceof Long) {
            return (Long) n;
        } else {
            return new Long(n.longValue());
        }
    }

    /**
     * Get cell value as float
     *
     * @param o EQL object
     * @return cell value
     */
    public static Float getFloat(EQLObject o) {
        Number n = getNumber(o);

        if(n == null) {
            return null;
        } else if(n instanceof Float) {
            return (Float) n;
        } else {
            return new Float(n.floatValue());
        }
    }

    /**
     * Get cell value as date
     *
     * @param o EQL object
     * @return cell value
     */
    public static Date getDate(EQLObject o) {
        return (Date) o.getObject();
    }

    /**
     * Get cell value as array of chars
     *
     * @param o EQL object
     * @return cell value
     */
    public static char[] getMemo(EQLObject o) {
        return (char[]) o.getObject();
    }

    /**
     * Get cell value as array of bytes
     *
     * @param o EQL object
     * @return cell value
     */
    public static byte[] getBinary(EQLObject o) {
        return (byte[]) o.getObject();
    }

    // Get string.
    public String toString() {
        return "reqField=" + reqField +
                " eqlObj=" + eqlObj +
                " oldEqlObj=" + oldEqlObj +
                " changed=" + changed +
                " isNull=" + isNull +
                " listFieldCell=[" + listFieldCell + "]";
    }

    // ========================================================= Private methods

    private void _setEQLObject(EQLObject newO) {
        if(newO == null) {
            throw new IllegalArgumentException();
        }

        eqlObj = newO;
        isNull = (newO instanceof EQLNullObject);
    }

}
