/**
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 *
 * Copyright (C)
 * <a href="http://www.inab.org">Spanish National Institute of Bioinformatics (INB)</a>
 * <a href="http://www.bsc.es">Barcelona Supercomputing Center (BSC)</a>
 * <a href="http://inb.bsc.es">Computational Node 6</a>
 */

package org.inb.biomoby.client.gui.ontology;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.LineMetrics;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.inb.biomoby.client.gui.AbstractMobyComponent;
import org.inb.biomoby.shared.datatypes.MobyInteger;
import org.inb.biomoby.shared.datatypes.MobyString;
import org.inb.biomoby.shared.ontology.StructureBoundaries;
import org.inb.biomoby.shared.ontology.StructureDomain;

/**
 * @author Dmitry Repchevsky
 */

public class StructureDomainComponent<T extends StructureDomain> extends AbstractMobyComponent<T>
{
    private final static int HEIGHT = 24;
    private final static int ROUND = HEIGHT/3;

    private final static Color TITLE_COLOR = new Color(0xFF00CC);
    private final static Color CHAIN_COLOR = new Color(0x0000FF);
    private final static Color FILL_COLOR = new Color(0x99FFFF);
    private final static Color BORDER_COLOR = new Color(0x3366FF);

    private ArrayList<Segment> segments;
    private final int min;
    private final int max;
    private final int dWidth;

    public StructureDomainComponent(T domain)
    {
        segments = new ArrayList<Segment>();

        List<? extends StructureBoundaries> boundaries = domain.getSegments();

        for (StructureBoundaries boundary : boundaries)
        {
            MobyInteger startMobyInteger = boundary.getStart();
            MobyInteger endMobyInteger = boundary.getEnd();

            if (startMobyInteger != null && endMobyInteger != null)
            {
                int start = startMobyInteger.getInteger();
                int end = endMobyInteger.getInteger();

                if (start > 0 && start < end)
                {
                    MobyString chainMobyString = boundary.getChain();

                    segments.add(new Segment(start, end, chainMobyString == null ? null : chainMobyString.getString()));
                }
            }

            Collections.sort(segments);
        }

        if (segments.isEmpty())
        {
            min = 0;
            max = 0;
        }
        else
        {
            min = segments.get(0).start;
            max = segments.get(segments.size() - 1).end; // ???
        }

        dWidth = max - min;
//        setLayout(new BorderLayout());
//
//        JTable table = new JTable(new StructureDomainTableModel(domain));
//        table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
//        table.setEnabled(false);
//
//        add(new JScrollPane(table), BorderLayout.CENTER);
    }

    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(super.getPreferredSize().width, HEIGHT);
    }

    @Override
    public Dimension getMaximumSize()
    {
        return new Dimension(super.getMaximumSize().width, HEIGHT);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        if (dWidth > 0)
        {
            Graphics2D g2d = (Graphics2D)g.create();

            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

            final int width = getWidth();
            final float xScale = width/(float)dWidth;

            for (Segment segment : segments)
            {
                final int x1 = (int)(xScale * (segment.start - min)) - 1;
                final int x2 = (int)(xScale * (segment.end - min)) - 1;

                g2d.setColor(FILL_COLOR);
                g2d.fillRoundRect(x1, 0, x2, HEIGHT - 1, ROUND, ROUND);
                
                g2d.setColor(BORDER_COLOR);
                g2d.drawRoundRect(x1, 0, x2, HEIGHT - 1, ROUND, ROUND);

                if (segment.chain != null && segment.chain.length() > 0)
                {
                    g2d.setColor(CHAIN_COLOR);

                    Font font = g2d.getFont();

                    LineMetrics lm = font.getLineMetrics(segment.chain, g2d.getFontRenderContext());
                    Rectangle2D rect = font.getStringBounds(segment.chain, g2d.getFontRenderContext());

                    final int w = x2 - x1;

                    if (w >= rect.getWidth())
                    {
                        g2d.drawString(segment.chain, (float)(x1 + ((w - rect.getWidth())/2)), HEIGHT - lm.getDescent());
                    }
                    else
                    {
                        Graphics2D _g = (Graphics2D)g2d.create();
                        _g.translate(x1, 0);
                        _g.scale(w/rect.getWidth(), 1);
                        _g.drawString(segment.chain, 0, HEIGHT - lm.getDescent());
                    }
                }
            }

            MobyString domainMobyString = getData().getName();
            if (domainMobyString != null)
            {
                String name = domainMobyString.getString();
                if (name != null && name.length() > 0)
                {
                    LineMetrics lm = g2d.getFont().getLineMetrics(name, g2d.getFontRenderContext());

                    g2d.setColor(TITLE_COLOR);
                    g2d.drawString(name, ROUND/2, lm.getAscent());
                }
            }
        }
    }

    private static class Segment implements Comparable<Segment>
    {
        public final int start;
        public final int end;
        public final String chain;

        public Segment(int start, int end, String chain)
        {
            this.start = start;
            this.end = end;
            this.chain = chain;
        }

        public int compareTo(Segment o)
        {
            return start == end ? 0 : start > end ? 1 : -1;
        }
    }
}
