/*
 * 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.chart;

import com.queplix.core.client.app.vo.FieldData;
import com.queplix.core.client.app.vo.chart.ChartData;
import com.queplix.core.client.app.vo.chart.ChartDataItem;
import com.queplix.core.client.app.vo.chart.ChartMeta;
import com.queplix.core.client.app.vo.chart.ChartType;
import com.queplix.core.client.common.CollectionsHelper;
import com.queplix.core.client.common.event.Event;
import com.queplix.core.client.common.event.EventSource;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Chart controller implementation
 *
 * @author Michael Trofimov
 */
public class QChartControllerImpl implements QChartController {

    private EventSource eventSource;

    private QChartModel model;
    private QChartView view;

    public QChartControllerImpl(QChartModel model, QChartView view) {
        this.model = model;
        this.view = view;
        view.addListener(new QChartView.ViewListener() {
            public void onChartClick(ChartDataItem item) {
                fireClickChartEvent(item);

            }

            public void onChartChangeType(ChartType type) {
                changeChartType(type);
            }

            public void onChartRefresh() {
                fireRequestChartDataEvent();
            }
        });
        eventSource = new EventSource(view.getWidget());
    }

    public EventSource getEventSource() {
        return eventSource;
    }

    /**
     * The descendants will override this method to setup proper chart filters
     */
    protected void setFiltersToModel(){
        // do nothing
    }
    
    protected QChartModel getModel(){
        return model;
    }

    protected QChartView getView(){
        return view;
    }

    private void fireRequestChartDataEvent(){
        setFiltersToModel();
        Event e = Events.CHART_REQUEST_DATA_EVENT;
        e.setData(model);
        eventSource.fireEvent(e);
    }

    private void fireClickChartEvent(ChartDataItem item) {
        Event e = Events.CHART_DRILLDOWN_CLICK_EVENT;
        e.setData(new ChartDrilldownClickEventDataImpl(model, item));
        eventSource.fireEvent(e);
    }

    private void changeChartType(ChartType type) {
        model.getMeta().setType(type);
        fireRequestChartDataEvent();
    }
    
    private static class ChartDrilldownClickEventDataImpl
            implements ChartDrilldownClickEventData {

        private String formId;
        private String[] filterFormIds;
        private Map/*<String, FieldData[]>*/ filters = new HashMap();

        public ChartDrilldownClickEventDataImpl(QChartModel model,
                                                ChartDataItem item) {
            ChartMeta meta = model.getMeta();
            ChartData data = model.getData();

            // Sets up form id
            int idx = data.getDataItems().indexOf(item);
            if(idx == -1) {
                throw new IllegalArgumentException(
                        "Passed wrong argument 'categoryFieldData' value");
            }

            List dataForms = meta.getDataFieldFormIds();
            int formsCount = dataForms.size();
            formId = (String) dataForms.get(
                    formsCount == 1 ? 0:idx % formsCount);

            setupFilters(meta, item);
        }

        public String[] getFilterFormIds() {
            return filterFormIds;
        }

        public FieldData[] getFilters(String formId) {
            return (FieldData[]) filters.get(formId);
        }

        public String getFormId() {
            return formId;
        }

        private void setupFilters(ChartMeta meta, ChartDataItem item) {
            // Prepare filters
            Map filters = new HashMap(meta.getFilters());   // clone map of filters
            String categoryFormId = meta.getCategoryFieldFormId();
            List filterList = (List) filters.get(categoryFormId); // clone list of filters
            filterList = filterList != null
                    ? filterList = new ArrayList(filterList) : new ArrayList/*<FieldData>*/();
            filters.put(categoryFormId, filterList);
            String categoryFieldId = item.getCategoryFieldData().getFieldID();
            for(Iterator it = filterList.iterator(); it.hasNext();) {
                FieldData fieldData = (FieldData) it.next();
                if(categoryFieldId.equals(fieldData.getFieldID())) {
                    filterList.remove(fieldData);
                    break;
                }
            }
            filterList.add(item.getCategoryFieldData());

            // Sets up array of form ids
            Set formIds = filters.keySet();
            filterFormIds = new String[formIds.size()];
            CollectionsHelper.copyToArray(formIds, filterFormIds);
            
            // Store lists of cloned FieldData objects to the map of filters
            for(Iterator it = formIds.iterator(); it.hasNext();) {
                String formId = (String) it.next();
                List list = (List) filters.get(formId);
                FieldData[] fieldData = new FieldData[list.size()];
                for(int i = 0; i < list.size(); i++) {
                    fieldData[i] = ((FieldData) list.get(i)).cloneData();
                }
                this.filters.put(formId, fieldData);
            }
        }

    }

}
