/*
 *                         Vortex OpenSplice
 *
 *   This software and documentation are Copyright 2006 to TO_YEAR ADLINK
 *   Technology Limited, its affiliated companies and licensors. All rights
 *   reserved.
 *
 *   Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 *   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 org.opensplice.common.model.table;

import java.util.Date;

import javax.swing.table.DefaultTableModel;

import org.opensplice.cm.data.GID;
import org.opensplice.cm.data.Message;
import org.opensplice.cm.data.Sample;
import org.opensplice.cm.data.State;

/**
 * Holds the Sample info of one specific Sample. The following information
 * is currently administrated:
 *
 * - node_state
 * - sample_state
 * - insert_time
 * - write_time
 * - write_insert_latency
 * - writerGID
 * - instanceGID
 * - sampleSequenceNumber
 *
 * @date Oct 21, 2004
 */
public class SampleInfoTableModel extends DefaultTableModel{
    private Sample currentValue = null;
    private boolean enabled = true;
    /**
     * Constructs new model that is capable of holding Sample info.
     */
    public SampleInfoTableModel(){
        super(0,0);
        this.initialize();
    }

    private void initialize(){
        Object[] data = new Object[2];

        this.addColumn("attribute");
        this.addColumn("value");
        data[1] = "N/A";

        /* 0 */
        data[0] = "sample_state";
        this.addRow(data);

        /* 1 */
        data[0] = "view_state";
        this.addRow(data);

        /* 2 */
        data[0] = "instance_state";
        this.addRow(data);

        /* 3 */
        data[0] = "valid_data";
        this.addRow(data);

        /* 4 */
        data[0] = "disposed_generation_count";
        this.addRow(data);

        /* 5 */
        data[0] = "no_writers_generation_count";
        this.addRow(data);

        /* 6 */
        data[0] = "insert_timestamp";
        this.addRow(data);

        /* 7 */
        data[0] = "source_timestamp";
        this.addRow(data);

        /* 8 */
        data[0] = "write_insert_latency";
        this.addRow(data);

        /* 9 */
        data[0] = "writerGID.localId";
        this.addRow(data);

        /* 10 */
        data[0] = "writerGID.systemId";
        this.addRow(data);

        /* 11 */
        data[0] = "instanceGID.localId";
        this.addRow(data);

        /* 12 */
        data[0] = "instanceGID.systemId";
        this.addRow(data);

        /* 13 */
        data[0] = "sampleSequenceNumber";
        this.addRow(data);

        /* 14 */
        data[0] = "qos.reliability.kind";
        this.addRow(data);

        /* 15 */
        data[0] = "qos.reliability.max_blocking_time";
        this.addRow(data);
    }

    public void setEnabled(boolean enabled){
        this.enabled = enabled;

        if(enabled){
            this.setData(this.currentValue);
        }
    }

    /**
     * Administrates the Sample info oof the supplied Sample. It replaces the
     * possible previous info.
     *
     * @param data The Sample, which info must be administrated.
     * @return true if the supplied Sample and its Message are not null, false
     *              otherwise.
     */
    public boolean setData(Sample data){
        currentValue = data;
        boolean success = false;

        if(enabled){
            int row = 0;

            if(data != null && data.getMessage() != null){
                Message msg = data.getMessage();
                State state = data.getState();

                this.setValueAt(this.getSampleState(state), row++, 1);
                this.setValueAt(this.getViewState(state), row++, 1);
                this.setValueAt(this.getInstanceState(state), row++, 1);
                this.setValueAt(this.getValidDataState(state), row++, 1);
                this.setValueAt(Long.toString(data.getDisposeCount()), row++, 1);
                this.setValueAt(Long.toString(data.getNoWritersCount()), row++, 1);

                String date = "(" + new Date(data.getInsertTimeSec() * 1000) + ")";
                this.setValueAt(Long.toString(data.getInsertTimeSec()) + "s. " +
                                Long.toString(data.getInsertTimeNanoSec()) + "ns. " +
                                date,
                                row++, 1);

                date = "(" + new Date(msg.getWriteTimeSec() * 1000) + ")";
                this.setValueAt(Long.toString(msg.getWriteTimeSec()) + "s. " +
                                Long.toString(msg.getWriteTimeNanoSec()) + "ns. " +
                                date,
                                row++, 1);

                long sec = data.getInsertTimeSec() - msg.getWriteTimeSec();
                long nsec = data.getInsertTimeNanoSec() - msg.getWriteTimeNanoSec();

                if(nsec < 0){
                    sec--;

                    String strNsec = Long.toString(nsec);
                    StringBuffer buf = new StringBuffer();
                    buf.append("1");
                    for (int i = 0; i < (strNsec.length() - 1); i++) {
                        buf.append("0");
                    }
                    String strOne = buf.toString();

                    long one = Long.parseLong(strOne);

                    /*Add up, because nsec is negative.*/
                    nsec = one + nsec;
                }

                this.setValueAt(Long.toString(sec) + "s. " + Long.toString(nsec)
                                + "ns.", row++, 1);

                GID gid = msg.getWriterGid();

                if(gid != null){
                    this.setValueAt(Long.toString(gid.getLocalId()), row++, 1);
                    this.setValueAt(Long.toString(gid.getSystemId()), row++, 1);
                } else {
                    this.setValueAt("N/A", row++, 1);
                    this.setValueAt("N/A", row++, 1);
                    this.setValueAt("N/A", row++, 1);
                }
                gid = msg.getInstanceGid();

                if(gid != null){
                    this.setValueAt(Long.toString(gid.getLocalId()), row++, 1);
                    this.setValueAt(Long.toString(gid.getSystemId()), row++, 1);
                } else {
                    this.setValueAt("N/A", row++, 1);
                    this.setValueAt("N/A", row++, 1);
                    this.setValueAt("N/A", row++, 1);
                }
                this.setValueAt(Long.toString(msg.getSampleSequenceNumber()), row++, 1);

                if(msg.getQos() != null){
                    this.setValueAt(msg.getQos().getReliabilityKind().toString(), row++, 1);
                } else {
                    this.setValueAt("N/A", row++, 1);
                }

                success = true;
            }
        } else {
            success = true;
        }
        return success;
    }

    public String getStringValueForRow(String name){
        String result = null;
        int rowCount = this.getRowCount();

        for(int i=0; (i<rowCount) && (result == null); i++){
            if(this.getValueAt(i,0).equals(name)){
                result = this.getValueAt(i,1).toString();
            }
        }
        return result;
    }

    /**
     * Makes sure the model cannot be edited.
     *
     * @param row The row that wants to be edited.
     * @param column The column that wants to be edited.
     */
    @Override
    public boolean isCellEditable(int row, int column){
        return false;
    }

    /**
     * Clears the model. The data is removed.
     */
    public synchronized void clear(){
        int rowCount = this.getRowCount();

        for(int i=0; i<rowCount; i++){
            this.setValueAt("N/A", i, 1);
        }
    }

    protected String getSampleState(State state){
        String result = null;

        if(state != null){
            int value = state.getValue();

            if((value & (State.READ)) == State.READ){
                result = "READ";
            } else {
                result = "NOT_READ";
            }
        } else {
            result = "N/A";
        }
        return result;
    }

    protected String getViewState(State state){
        String result = null;

        if(state != null){
            int value = state.getValue();

            if((value & (State.NEW)) == State.NEW){
                result = "NEW";
            } else {
                result = "NOT_NEW";
            }
        } else {
            result = "N/A";
        }
        return result;
    }

    protected String getInstanceState(State state){
        String result = null;

        if(state != null){
            int value = state.getValue();

            if((value & (State.DISPOSED)) == State.DISPOSED){
                result = "NOT_ALIVE_DISPOSED";
            } else if((value & (State.NOWRITERS)) == State.NOWRITERS){
                result = "NOT_ALIVE_NO_WRITERS";
            } else {
                result = "ALIVE";
            }
        } else {
            result = "N/A";
        }
        return result;
    }

    protected String getValidDataState(State state){
        String result = null;

        if(state != null){
            int value = state.getValue();

            if((value & (State.VALIDDATA)) == State.VALIDDATA){
                result = "TRUE";
            } else {
                result = "FALSE";
            }
        } else {
            result = "N/A";
        }
        return result;
    }
}
