package com.queplix.core.client.controls.charts;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.LoadListener;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.queplix.core.client.app.vo.ChartFieldMeta;
import com.queplix.core.client.app.vo.ChartFieldOnDemandData;
import com.queplix.core.client.app.vo.chart.ChartDataItem;
import com.queplix.core.client.app.vo.chart.ChartType;
import com.queplix.core.client.common.ui.ImageMap;
import com.queplix.core.client.common.ui.ImageMapArea;
import com.queplix.core.client.common.ui.MappedImage;
import com.queplix.core.client.controls.QFormElement;
import com.queplix.core.client.i18n.I18N;

class QChartViewImpl extends QChartView {

    private QChartModelImpl model;

    private MappedImage chartImage;
    private ImageMap chartMap;

    // Provides uniqueness to image map name
    private static int uniqueId;

    // Contains RadioButton associated with its type name, @see ChartType#getName
    private Map typeButtons/*<RadioButton, String>*/
            = new HashMap/*<RadioButton, String>*/();

    // RadioButton that represents current chart type
    private RadioButton currentTypeButton;

    private ClickListener refreshListener = new ClickListener() {
        public void onClick(Widget sender) {
            fireDataRequested();
        }
    };
    
    public QChartViewImpl(QChartModelImpl model, int layout) {
        super(model, layout);
        this.model = model;
//        eventHandlers = new ArrayList();
//        initGUIVisible();
//        subscribeEvents();
        initializeUI();
    }

    public void onModelDataChanged() {
        super.onModelDataChanged();
        if (model.getData().isEmpty()) {
            setEmptyChart();
        } else {
            fireDataRequested();
        }
    }

    protected void setEmptyChart() {
        // TODO optimization - cache "empty" chart images
        fireEmptyDataRequested();
    }

    public void onDemandModelChanged() {
        super.onDemandModelChanged();
        applyChartData();
    }

    private void applyChartData() {
        ChartFieldOnDemandData data
                = (ChartFieldOnDemandData) model.getFieldOnDemandData();

        // Sets up chart type radio buttons
        String typeName = data.getChartType().getName();
        for(Iterator it = typeButtons.keySet().iterator(); it.hasNext();) {
            RadioButton typeButton = (RadioButton) it.next();
            typeButton.setChecked(typeButtons.get(typeButton).equals(typeName));
            if(typeButton.isChecked())
                currentTypeButton = typeButton;
        }

        // Adds areas to the image map
        chartMap.clear();
        ChartDataItem[] items = data.getDataItems();
        for(int i = 0; i < items.length; i++) {
            final ChartDataItem item = items[i];
            ImageMapArea area = chartMap.addArea(
                    item.getShape(), item.getCoords());
            area.setTitle(item.getTitle());
            area.addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    fireChartClicked(item);
                }
            });
        }

        // Sets up chart image url
        chartImage.setUrl(data.getChartUrl());
// TODO check it later
//        chartImage.setWidth(model.getMeta().getWidth() + "px");
//        chartImage.setHeight(model.getMeta().getHeight() + "px");
    }


    protected MappedImage getChartImage(){
        return chartImage;
    }
    
    protected ImageMap getChartImageMap(){
        return chartMap;
    }
    
    protected void initializeUI() {
//        super.initializeBaseUI(QFormElement.HORIZONTAL);
        super.initializeBaseUI(QFormElement.VERTICAL);

        ChartFieldMeta chartMeta = model.getMeta();

        VerticalPanel chartPanel = new VerticalPanel();
        chartPanel.setSpacing(2);
        chartPanel.addStyleName("chart_panel");
        addToPanel(chartPanel);

        HorizontalPanel row0 = new HorizontalPanel();
        row0.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
        row0.setWidth("100%");

        // Chart type panel
        HorizontalPanel typePanel = new HorizontalPanel();
        for(int i = 0; i < ChartType.TYPES.length; i++) {
            ChartType type = ChartType.TYPES[i];

            RadioButton typeButton = new RadioButton(
                    "chartType" + chartMeta.getChartName());
            typeButton.setHTML(QChart.getChartTypeTitle(type) + "&nbsp;");
            typeButton.addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    fireChangeTypeEvent(sender);
                }
            });
            typePanel.add(typeButton);

            typeButtons.put(typeButton, type.getName());

        }
        row0.add(typePanel);
        row0.setCellHorizontalAlignment(
                typePanel, HasHorizontalAlignment.ALIGN_LEFT);

        // Refresh panel
        HorizontalPanel refreshPanel = new HorizontalPanel();
        refreshPanel.setSpacing(2);
        refreshPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);

        Image refreshIcon = new Image("chart/refresh.gif");
        refreshIcon.addClickListener(refreshListener);
        refreshPanel.add(refreshIcon);

        HTML refreshLink = new HTML(
                "&nbsp;" + I18N.getMessages().chartsRefreshLabel(), false);
        refreshLink.addStyleName("chart_refresh_link");
        refreshLink.addClickListener(refreshListener);
        refreshPanel.add(refreshLink);

        row0.add(refreshPanel);
        row0.setCellHorizontalAlignment(
                refreshPanel, HasHorizontalAlignment.ALIGN_RIGHT);

        chartPanel.add(row0);

        HorizontalPanel imagePanel = new HorizontalPanel();
        imagePanel.addStyleName("chart_image_panel");

        chartMap = new ImageMap("imagemap" + uniqueId++);
        imagePanel.add(chartMap);

        chartImage = new MappedImage();
        chartImage.addStyleName("chart_image");
        chartImage.setVisible(false);
        // TODO chart image's load listener should be customizable
        chartImage.addLoadListener(new LoadListener() {
            public void onLoad(Widget sender) {
                // TODO hide "Loading..." message
                if(!chartImage.isVisible()) {
                    chartImage.setVisible(true);
                }
            }

            public void onError(Widget sender) {
                // TODO display onerror message and broken chart picture (prefetch it)
                Window.alert("Unable load chart image "
                        + model.getOnDemandData().getChartUrl());
            }
        });
        chartImage.setMap(chartMap);
        imagePanel.add(chartImage);

        imagePanel.setCellHorizontalAlignment(
                chartImage, HasHorizontalAlignment.ALIGN_CENTER);
        imagePanel.setCellVerticalAlignment(
                chartImage, HasVerticalAlignment.ALIGN_MIDDLE);

        chartPanel.add(imagePanel);

        initPanel();
    }

    private void fireChangeTypeEvent(Widget sender) {
        if(sender instanceof RadioButton && !currentTypeButton.equals(sender)) {
            ChartType newType = ChartType.valueOf(
                    (String) typeButtons.get(sender));
            if(newType == null) {
                throw new IllegalStateException(
                        "Cannot find ChartType by widget " + sender);
            }

            fireChartTypeChanged(newType);

            currentTypeButton = (RadioButton) sender;
        }
    }

    protected void setEnabled(boolean isEnabled) {
        // this control can't be enabled or disabled
    }

    public int getClientWidth() {
        // TODO Auto-generated method stub
        return 0;
    }

    protected void setClientWidth(String clientWidth) {
        // TODO Auto-generated method stub

    }

}
