/*
 * #%L
 * gitools-core
 * %%
 * Copyright (C) 2013 Universitat Pompeu Fabra - Biomedical Genomics group
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */
package org.gitools.ui.app.heatmap.drawer.header;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.gitools.heatmap.Heatmap;
import org.gitools.heatmap.HeatmapDimension;
import org.gitools.heatmap.header.HeatmapColoredLabelsHeader;
import org.gitools.heatmap.header.HeatmapDecoratorHeader;
import org.gitools.heatmap.header.HeatmapHeader;
import org.gitools.heatmap.header.HeatmapTextLabelsHeader;
import org.gitools.ui.app.heatmap.drawer.AbstractHeatmapDrawer;
import org.gitools.ui.app.heatmap.drawer.AbstractHeatmapHeaderDrawer;
import org.gitools.ui.core.HeatmapPosition;

import java.awt.*;
import java.util.*;
import java.util.List;

public class HeatmapHeaderIntersectionDrawer extends AbstractHeatmapDrawer {


    private final HeatmapHeaderDrawer colDrawer;
    private final HeatmapHeaderDrawer rowDrawer;

    private Multimap headerLegendDrawers;

    private Map<Object, Integer> XCoordinates;
    private Map<Object, Integer> YCoordinates;

    /* Map that contains the header that are responsible for drawing the
    * legend of a header from the other dimension (row,cols) as for example:
    * HeatmapColoredLabelsHeader --> draws for --> HeatmapDataHeatmapHeader */

    private static final Map<Class<?>, Class<?>> headerRelationsMap = new HashMap<>();

    static {
        headerRelationsMap.put(HeatmapColoredLabelsHeader.class, HeatmapDecoratorHeader.class);
        headerRelationsMap.put(HeatmapTextLabelsHeader.class, HeatmapDecoratorHeader.class);
    }


    public HeatmapHeaderIntersectionDrawer(Heatmap heatmap, HeatmapHeaderDrawer colDrawer, HeatmapHeaderDrawer rowDrawer) {
        super(heatmap);

        this.colDrawer = colDrawer;
        this.rowDrawer = rowDrawer;


        updateDrawers(null);
    }

    private boolean isCompatiblePair(HeatmapHeader thisHeader, HeatmapHeader oppositeHeader) {
        boolean answer = false;
        if (headerRelationsMap.get(thisHeader.getClass()) == oppositeHeader.getClass()) {
            String pattern1 = thisHeader.getAnnotationPattern();
            String pattern2 = oppositeHeader.getAnnotationPattern();
            answer = pattern1 != null && pattern2 != null &&
                    thisHeader.getAnnotationPattern().equals(oppositeHeader.getAnnotationPattern());
        }
        return answer;
    }

    public final void updateDrawers(HeatmapDimension evtSrc) {

        if (getHeatmap().getRows() == evtSrc) {
            rowDrawer.update();
        }

        if (getHeatmap().getColumns() == evtSrc) {
            colDrawer.update();
        }
        getHeaderDrawers();
    }

    private void getHeaderDrawers() {
        XCoordinates = new HashMap<>();
        YCoordinates = new HashMap<>();
        List<AbstractHeatmapHeaderDrawer> colHeaderDrawers = colDrawer.getDrawers();
        List<AbstractHeatmapHeaderDrawer> rowHeaderDrawers = rowDrawer.getDrawers();
        List<HeatmapHeader> rowHeaders = getHeatmap().getRows().getHeaders();
        List<HeatmapHeader> colHeaders = getHeatmap().getColumns().getHeaders();
        headerLegendDrawers = HashMultimap.create();

        int XPosition = 0;
        for (AbstractHeatmapHeaderDrawer d : rowHeaderDrawers) {
            HeatmapHeader thisH = rowHeaders.get(rowHeaderDrawers.indexOf(d));
            XCoordinates.put(d, XPosition);
            XCoordinates.put(thisH, XPosition);
            for (HeatmapHeader oppositeH : colHeaders) {
                if (isCompatiblePair(thisH, oppositeH)) {
                    headerLegendDrawers.put(d, oppositeH);
                }
            }
            XPosition += d.getSize().width;
        }


        int colHeaderSize = 0;
        for (AbstractHeatmapDrawer d : colHeaderDrawers) {
            colHeaderSize += d.getSize().height;
        }
        for (AbstractHeatmapDrawer d : colHeaderDrawers) {
            HeatmapHeader thisH = colHeaders.get(colHeaderDrawers.indexOf(d));
            int size = d.getSize().height;
            colHeaderSize -= size;
            YCoordinates.put(d, colHeaderSize);
            YCoordinates.put(thisH, colHeaderSize);
            for (HeatmapHeader oppositeH : rowHeaders) {
                if (isCompatiblePair(thisH, oppositeH)) {
                    headerLegendDrawers.put(d, oppositeH);
                }
            }
        }
    }


    @Override
    public Dimension getSize() {
        return new Dimension(rowDrawer.getSize().width, colDrawer.getSize().height);
    }

    @Override
    public void draw(Graphics2D g, Rectangle box, Rectangle clip) {

        // Clear background
        g.setColor(Color.WHITE);
        g.fillRect(clip.x, clip.y, clip.width, clip.height);

        Dimension d = getSize();

        int width = d.width < box.width ? d.width : box.width;
        int height = box.height;
        
      /* g.setColor(Color.pink);
        g.fillRect(box.x,box.y,width,height);        */

        drawHeaderIntersection(g, new Rectangle(box.x, box.y, width, height));

    }


    @Override
    public HeatmapPosition getPosition(Point p) {
        return new HeatmapPosition(getHeatmap(), colDrawer.getSize().width, 0);
    }


    @Override
    public Point getPoint(HeatmapPosition p) {
        return new Point(0, 0);
    }


    void drawHeaderIntersection(Graphics2D g, Rectangle headerIntersection) {

        getHeaderDrawers();

        if (headerLegendDrawers == null || headerLegendDrawers.size() == 0) {
            return;
        }

        Set legendDrawers = headerLegendDrawers.keySet();
        for (Object d : legendDrawers) {
            AbstractHeatmapHeaderDrawer drawer = (AbstractHeatmapHeaderDrawer) d;
            Collection headers = headerLegendDrawers.get(d);
            for (Object h : headers) {
                HeatmapHeader header = (HeatmapHeader) h;

                if (!header.isVisible()) {
                    continue;
                }

                int x;
                int y;
                int width;
                int height;
                if (drawer.isHorizontal()) {
                    x = XCoordinates.get(header);
                    y = YCoordinates.get(drawer);
                    width = header.getSize();
                    height = drawer.getSize().height;
                } else {
                    x = XCoordinates.get(drawer);
                    y = YCoordinates.get(header);
                    width = drawer.getSize().width;
                    height = header.getSize();
                }
                Rectangle legendLimits = new Rectangle(x + headerIntersection.x, y + headerIntersection.y, width, height);
                drawer.drawHeaderLegend(g, legendLimits, header);
            }
        }


    }

}
