/*
 * 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.client.controls.grid;

import com.queplix.core.client.app.vo.GridData;
import com.queplix.core.client.app.vo.GridMeta;
import com.queplix.core.client.app.vo.RowData;
import com.queplix.core.client.app.vo.SortField;
import com.queplix.core.client.app.vo.SortFieldImpl;
import com.queplix.core.client.app.vo.SubsetData;
import com.queplix.core.client.app.vo.uisettings.GridUISettings;
import com.queplix.core.client.common.ui.grid.BaseGridModel;
import com.queplix.core.client.common.ui.grid.DataGridMeta;
import com.queplix.core.client.common.ui.grid.DataGridMetaImpl;
import com.queplix.core.client.common.ui.grid.GridDataProvider;
import com.queplix.core.client.common.ui.grid.GridModel;
import com.queplix.core.client.common.ui.grid.SortColumn;
import com.queplix.core.client.common.ui.grid.TextGridDataProvider;

import java.util.ArrayList;

/**
 * This class contais response data for Load Report Request.
 *
 * @author Sergey Kozmin
 * @since 19 September 2006
 */
class QGridModelImpl implements QGridModel {
    private final static int DEFAULT_PAGE_SIZE = 20;
    private final static boolean DEAFULT_COUNTER_ON = false;
    private final static int UNKNOWN_PAGE_COUNT = 0;

    private GridMeta metaData;
    private GridData data;
    private TextGridDataProvider dataProviderForGrid;
    private DataGridMeta dataGridMeta;

    private long recordsTotal;
    private long pagesCount = UNKNOWN_PAGE_COUNT;
    private long currentPage;

    private boolean counterToggledOn = DEAFULT_COUNTER_ON;
    private int pageSize = DEFAULT_PAGE_SIZE;

    private ArrayList qgridListeners = new ArrayList();

    private BaseGridModel gridModelImpl;

    /**
     * Indicate selected row in grid.
     */
    private Long selectedRecordId;
    /**
     * Indicate, should pager be updated
     */
    private boolean pagerToBeUpdated;

    public QGridModelImpl(GridMeta meta) {
        gridModelImpl = new QDataGridModel();
        initFromUISettings(meta);
        setMetaData(meta);
    }

    public int getModelRowCount() {
        if(data != null) {
            return data.getRows().length;
        } else {
            return 0;
        }
    }

    public int getModelColumnCount() {
        if(metaData != null) {
            return metaData.getColumnsCount();
        } else {
            return 0;
        }
    }

    public void setMetaData(GridMeta metaData) {
        this.metaData = metaData;
        dataGridMeta = DataGridMetaImpl.createDataGridMeta(metaData);
        gridModelImpl.fireDataStructureChanged();
        setPagerData(0, 0);
        fireSelectedRecordChanged(selectedRecordId);
    }

    public GridMeta getIncomingMetaData() {
        return metaData;
    }

    public void setGridData(GridData data) {
        setGridData(data, UNKNOWN_PAGE_COUNT, 0);
    }

    public void setGridData(GridData data, long recordsTotal,
                            long currentPage) {
        this.data = data;
        initDataProvider(data);
        gridModelImpl.fireDataChanged();
        setPagerData(recordsTotal, currentPage);
        fireSelectedRecordChanged(selectedRecordId);
    }

    private void initDataProvider(GridData data) {
        if(dataProviderForGrid != null) {
            dataProviderForGrid.setData(data);
        } else {
            dataProviderForGrid = new TextGridDataProvider(data);
            gridModelImpl.setDataProvider(dataProviderForGrid);
        }
    }

    private void setPagerData(long recordsTotal, long currentPage) {
        pagerToBeUpdated = pagerToBeUpdated || (this.recordsTotal
                != recordsTotal);
        this.recordsTotal = recordsTotal;
        pagerToBeUpdated = pagerToBeUpdated || (this.currentPage
                != currentPage);
        this.currentPage = currentPage;
        this.pagesCount = (long) Math.ceil(recordsTotal / (float) pageSize);

        if(pagerToBeUpdated) {
            firePagerDataChanged();
            pagerToBeUpdated = false;
        }
    }

    public void setRowData(RowData rowData) {
        if(rowData != null) {
            if(data == null) {
                setGridData(new GridData(new RowData[]{rowData}, ""));
            }
            int rowIndex = data.getRowIndexByID(rowData.getId());
            if(rowIndex >= 0) {
                data.getRows()[rowIndex].copyFrom(rowData);
                gridModelImpl.fireRowDataChanged(rowIndex);
                fireSelectedRecordChanged(selectedRecordId);
            } else {
                data.insertRow(rowData);
                gridModelImpl.fireRowsWereInserted();
                fireSelectedRecordChanged(selectedRecordId);
                firePagerDataChanged(); // number of loaded records changed
            }
        }
    }

    public void setSelectedRecordId(Long selectedRecordId) {
        if(this.selectedRecordId != null) {
            if(!this.selectedRecordId.equals(selectedRecordId)) {
                this.selectedRecordId = selectedRecordId;
//                fireSelectedRecordChanged(selectedRecordId);
            }
        } else {
            if(selectedRecordId != null) {
                this.selectedRecordId = selectedRecordId;
//                fireSelectedRecordChanged(selectedRecordId);
            }
        }
        fireSelectedRecordChanged(selectedRecordId);
    }

    public Long getRecordIdByRow(int row) {
        GridData gridData = getGridData();
        return gridData.getRows()[row].getId();
    }

    public int getRowByRecordId(Long recordId) {
        int ret = -1;
        GridData gridData = getGridData();
        if(gridData != null) {
            ret = gridData.getRowIndexByID(recordId);
        }
        return ret;
    }

    public Long getSelectedRecordId() {
        return selectedRecordId;
    }

    public GridDataProvider getData() {
        return dataProviderForGrid;
    }

    public GridData getGridData() {
        return data;
    }

    public void setRecordsTotal(long recordsTotal) {
        if(this.recordsTotal != recordsTotal) {
            this.recordsTotal = recordsTotal;
        }
    }

    public long getRecordsTotal() {
        return recordsTotal;
    }

    public long getPagesCount() {
        return pagesCount;
    }

    public void setPagesCount(long pagesCount) {
        this.pagesCount = pagesCount;
    }

    public long getCurrentPage() {
        return currentPage;
    }

    public SortField getSortField() {
        return gridModelImpl.getSortField();
    }

    public SortFieldImpl getSortFieldImpl() {
        return gridModelImpl.getSortFieldImpl();
    }

    public SortColumn getSortColumn() {
        return gridModelImpl.getSortColumn();
    }

    public void setCurrentPage(long currentPage) {
        if(this.currentPage != currentPage) {
            this.currentPage = currentPage;
            pagerToBeUpdated = true;
        }
    }

    public boolean isCounterToggledOn() {
        return counterToggledOn;
    }

    public void setCounterToggledOn(boolean counterToggledOn) {
        if(this.counterToggledOn != counterToggledOn) {
            this.counterToggledOn = counterToggledOn;
            pagerToBeUpdated = true;
        }
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        if(this.pageSize != pageSize) {
            this.pageSize = pageSize;
            pagerToBeUpdated = true;
        }
    }

    public void addPagerModelListener(QGridListener listener) {
        qgridListeners.add(listener);
    }

    public void removePagerModelListener(QGridListener listener) {
        qgridListeners.remove(listener);
    }

    private void fireSelectedRecordChanged(Long newRecordSelectedId) {
        for(int i = 0; i < qgridListeners.size(); i++) {
            QGridListener listener = (QGridListener) qgridListeners.get(i);
            listener.selectedRecordChanged(newRecordSelectedId);
        }
    }

    private void firePagerDataChanged() {
        for(int i = 0; i < qgridListeners.size(); i++) {
            QGridListener listener = (QGridListener) qgridListeners.get(i);
            listener.pageDataIsChanged();
        }
    }

    public DataGridMeta getDataGridMeta() {
        return dataGridMeta;
    }

    public void customizeGrid(SubsetData data) {
        metaData.getColumns().setSelectedIDs(
                data.getSelectedIDs()); // update meta data
        this.data = new GridData();
        dataGridMeta = DataGridMetaImpl.createDataGridMeta(dataGridMeta,
                metaData);
        gridModelImpl.fireDataStructureChanged();
    }

    private void initFromUISettings(GridMeta meta) {
        GridUISettings uiSettings = meta.getUISettings();
        if(uiSettings != null) {
            counterToggledOn = uiSettings.isCounterOn();
            if(uiSettings.isPageSizeSet()) {
                pageSize = uiSettings.getPageSize();
            }
        }
    }

    void collectUISettings() {
        if(haveUISettingsChanged()) {
            GridUISettings uiSettings = metaData.getOrCreateUISettings();
            uiSettings.setCounterOn(counterToggledOn);
            if(isPageSizeSet()) {
                uiSettings.setPageSize(pageSize);
            }
            DataGridMetaImpl.collectUISettings(dataGridMeta, metaData);
        }
    }

    private boolean haveUISettingsChanged() {
        return isPageSizeSet() || (counterToggledOn != DEAFULT_COUNTER_ON)
                || anyColumnWasResized();
    }

    private boolean anyColumnWasResized() {
        boolean isResized = false;

        long[] ids = metaData.getColumns().getSelectedIDs();
        for(int i = 0; i < ids.length; i++) {
            if(dataGridMeta.getColumn(i).isResized()) {
                isResized = true;
                break;
            }
        }
        return isResized;
    }

    private boolean isPageSizeSet() {
        return (pageSize != DEFAULT_PAGE_SIZE);
    }


    public GridModel getGridModelImpl() {
        return gridModelImpl;
    }

    private class QDataGridModel extends BaseGridModel {
        protected GridData getData() {
            return data;
        }

        protected GridMeta getMeta() {
            return metaData;
        }

        public DataGridMeta getDataGridMeta() {
            return dataGridMeta;
        }
    }
}