/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2007-2015 Broad Institute
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.broad.igv.peaks;

import org.broad.igv.data.DataSource;
import org.broad.igv.feature.LocusScore;
import org.broad.igv.renderer.BarChartRenderer;
import org.broad.igv.renderer.Renderer;
import org.broad.igv.track.RenderContext;
import org.broad.igv.track.Track;
import org.broad.igv.ui.color.ColorUtilities;

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

/**
 * @author jrobinso
 * @date Apr 23, 2011
 */
public class PeakRenderer implements Renderer<LocusScore> {

    BarChartRenderer chartRenderer = new BarChartRenderer();
    public static final int SIGNAL_CHART_HEIGHT = 15;

    public void render(List<LocusScore> peakList, RenderContext context, Rectangle rect, Track t) {


        PeakTrack track = (PeakTrack) t;

        final double locScale = context.getScale();
        final double origin = context.getOrigin();

        int lastPX = -1;
        double pXMin = rect.getMinX();
        double pXMax = rect.getMaxX();

        Color fgColor = track.getColor();
        Graphics2D borderGraphics = context.getGraphic2DForColor(Color.black);

        String chr = context.getChr();
        int contextStart = (int) context.getOrigin();
        int contextEnd = (int) context.getEndLocation();
        int zoom = context.getZoom();

        if (PeakTrack.isShowPeaks()) {
            int h = track.bandHeight;
            int peakHeight = PeakTrack.isShowSignals() ? track.peakHeight : h;

            for (LocusScore ls : peakList) {
                Peak peak = (Peak) ls;

                int start = peak.getStart();
                int end = peak.getEnd();
                int pX = (int) ((start - origin) / locScale);
                int dX = (int) Math.max(2, (end - start) / locScale);

                if (pX + dX < pXMin) continue;
                if (pX > pXMax) break;

                float score = peak.getCombinedScore();
                if (PeakTrack.getColorOption() == PeakTrack.ColorOption.FOLD_CHANGE) {
                    score = peak.getDynamicScore();
                }

                int top = rect.y + 1;
                if (PeakTrack.isShowSignals()) {
                    top += track.signalHeight;
                }

                if (PeakTrack.animate) {
                    int step = track.getTimeStep();
                    float[] timeScores = peak.getTimeScores();
                    int idx = Math.min(step, timeScores.length - 1);
                    score = timeScores[idx];
                    drawPeak(context, fgColor, pX, dX, top, peakHeight, score, PeakTrack.getColorOption());
                } else {
                    if (track.getDisplayMode() == Track.DisplayMode.EXPANDED) {
                        float[] timeScores = peak.getTimeScores();
                        for (int i = 0; i < timeScores.length; i++) {
                            score = timeScores[i];
                            drawPeak(context, fgColor, pX, dX, top, peakHeight, score, PeakTrack.getColorOption());
                            top += h;
                        }
                    } else {
                        drawPeak(context, fgColor, pX, dX, top, peakHeight, score, PeakTrack.getColorOption());

//                    float[] timeScores = peak.getTimeScores();
//                    if (dX > 10 && timeScores.length > 1) {
//                        Graphics2D gLine = context.getGraphic2DForColor(Color.black);
//                        gLine.setRenderingHint(RenderingHints.KEY_ANTIALIASING,IGVPreferences.getInstance().getAntiAliasingHint());
//                        double deltaX = ((double) dX / (timeScores.length - 1));
//                        double scaleY = peakHeight / 200.0;
//                        int bottomY = top + peakHeight;
//                        int lastX = pX;
//                        int lastY = (bottomY - (int) (scaleY * timeScores[0]));
//                        for (int i = 1; i < timeScores.length; i++) {
//                            score = timeScores[i];
//                            int x = pX + (int) (i * deltaX);
//                            int y = Math.max(top + 2, (int) (bottomY - (int) (scaleY * timeScores[i])));
//                            gLine.drawLine(lastX, lastY, x, y);
//                            lastX = x;
//                            lastY = y;
//
//                        }
//                    }
                    }
                }
            }
        }

        if (PeakTrack.isShowSignals() && track.getSignalPath() != null) {
            int h = track.bandHeight;
            int signalHeight = PeakTrack.isShowPeaks() ? track.signalHeight : h;

            if (PeakTrack.animate) {
                int step = track.getTimeStep();
                DataSource[] timeSignalSources = track.getTimeSignalSources();
                int idx = Math.min(step, timeSignalSources.length - 1);
                DataSource src = timeSignalSources[idx];
                if (src != null) {
                    int top = rect.y + 2;List<LocusScore> timeSignals = src.getSummaryScoresForRange(chr, contextStart, contextEnd, zoom);
                    Rectangle timeSignalRect = new Rectangle(rect.x, top, rect.width, signalHeight - 1);
                    chartRenderer.render(timeSignals, context, timeSignalRect, track);
                }
            } else {
                if (track.getDisplayMode() == Track.DisplayMode.EXPANDED) {

                    DataSource[] timeSignalSources = track.getTimeSignalSources();
                    if (timeSignalSources != null) {
                        int top = rect.y + 2;
                        for (int i = 0; i < timeSignalSources.length; i++) {
                            DataSource src = timeSignalSources[i];
                            if (src != null) {
                                List<LocusScore> timeSignals = src.getSummaryScoresForRange(chr, contextStart, contextEnd, zoom);
                                Rectangle timeSignalRect = new Rectangle(rect.x, top, rect.width, signalHeight - 1);
                                chartRenderer.render(timeSignals, context, timeSignalRect, track);
                            }
                            top += h;

                        }
                    }
                } else {
                    final PeakTrack.WrappedDataSource signalSource = track.getSignalSource(chr, contextStart, contextEnd, zoom);
                    if (signalSource != null) {
                        List<LocusScore> signals = signalSource.getSummaryScoresForRange(chr, contextStart, contextEnd, zoom);
                        Rectangle signalRect = new Rectangle(rect.x, rect.y + 1, rect.width, signalHeight - 1);
                        chartRenderer.render(signals, context, signalRect, track);
                    }
                }
            }
        }


        if (track.getDisplayMode() == Track.DisplayMode.EXPANDED) {
            borderGraphics.drawLine(rect.x, rect.y, rect.x + rect.width, rect.y);
            borderGraphics.drawLine(rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height);
        }
    }


    private void drawPeak(RenderContext context, Color fgColor,
                          int pX, int dX, int top, int h, float score, PeakTrack.ColorOption option) {
        Color c = getColor(fgColor, score, option);
        Graphics2D g = context.getGraphic2DForColor(c);
        g.fillRect(pX, top + 1, dX, h - 2);

    }

    private Color getColor(Color fgColor, float score, PeakTrack.ColorOption option) {
        Color c = null;
        float alpha = 1.0f;
        if (option == PeakTrack.ColorOption.SCORE) {
            // scale is 1 -> 100
            int shadeStep = (int) (score / 10);
            alpha = Math.max(0.2f, (Math.min(1.0f, shadeStep * 0.1f)));

        } else if (option == PeakTrack.ColorOption.FOLD_CHANGE) {

            // Scale is 1.58 -> 3.3 log2
            if (Math.abs(score) < 1.58) {
                alpha = 1f;
                fgColor = Color.gray;
            } else {
                // vary alpha from .3 -> 1 over range 3.3 -> 1.58 in steps of 10
                int shadeStep = (int) ((Math.abs(score) - 1.58) / (3.3 - 1.58) * 10);
                alpha = Math.max(0.3f, (Math.min(1f, 0.3f + shadeStep * 0.1f)));
                fgColor = (score < 0 ? Color.blue : Color.red);
            }
        }

        c = ColorUtilities.getCompositeColor(fgColor, alpha);
        //}
        return c;
    }
}
