/*
Copyright 2005-2013 Samuel Gesche

This file is part of ArcEnCiel.

ArcEnCiel 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.

ArcEnCiel 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 ArcEnCiel.  If not, see <http://www.gnu.org/licenses/>.
*/

package ihm.townto;

import data.ListeSynonymes;
import ihm.Charte;
import ihm.Legende;

import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.util.Vector;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.Cursor;
import java.awt.Component;
import java.net.URISyntaxException;
import java.net.URI;
import java.io.File;
import java.awt.Image;
import javax.swing.ImageIcon;
import java.net.MalformedURLException;

/**
 * @author Samuel GESCHE
 * @version 3.0
 */
public class MultiPVGraphPanel extends GraphPanel {
    private Legende legende;

    public MultiPVGraphPanel(int nbPV, MultiPVGraph gd, int id) {
        super(gd, id);
        legende = new Legende(nbPV);
        setGraph(gd);
    }

    public void setGraph(MultiPVGraph gd) {
        //quaker.stop();
        createStuff(gd);
        layout.invalidate();
        for (int i = 0; i < 100 / gd.getNumberOfNodes(); i++) {
            doLayout();
        }
        //quaker.start();
    }

    /**
     * Dit si le second noeud est dans la couronne du premier.
     * @param firstCrownNode Node un noeud
     * @param secondCrownNode Node un noeud
     * @return boolean le résultat du calcul
     * @since 3.0.0
     */
    boolean isInCrownOf(Node firstNode, Node secondNode) {
        boolean yes = false;
        if (isActiveNode(firstNode) && isInFirstCrown(secondNode) ||
            isActiveNode(firstNode) && isInSecondCrown(secondNode)){
            yes = true;
        }
        if(!yes && isInFirstCrown(firstNode)){
            Node[] liste = getSecondCrown(firstNode);
            for(int i=0; i<liste.length; i++){
                if(liste[i].getId() == secondNode.getId()){
                    yes = true;
                    break;
                }
            }
        }
        /*int id1 = firstNode.getId();
        int id2 = secondNode.getId();
        for (int i = 0; i < links.length; i++) {
            if ((links[i].getNode1().getId() == id1 &&
                 links[i].getNode2().getId() == id2)) {
                yes = true;
                break;
            }
            for(int j = 0; j < links.length; j++){
                if (links[i].getNode1().getId() == id1 &&
                    links[i].getNode2().getId() == links[j].getNode1().getId() &&
                    links[j].getNode2().getId() == id2){
                    yes = true;
                    break;
                }
            }
            if(yes){
                break;
            }
        }*/
        return yes;
    }


    protected void createStuff(MultiPVGraph gd) {
        processing = true;
        removeAll();

        // Creating Nodes from the Graph.GraphNodes of the Graph

        activeNode = new MultiPVNode(gd.getMultiPVActive().getListe(),
                                     gd.getMultiPVActive().getDescription(),
                                     gd.getMultiPVActive().getId(),
                                     this);
        activeNode.setBorder(Charte.getBorder());
        add(activeNode);

        MultiPVGraph.MultiPVGraphNode[] nodes1 = gd.getMultiPVSortedFirstCrown();
        crown1 = new MultiPVNode[nodes1.length];
        for (int i = 0; i < crown1.length; i++) {
            crown1[i] = new MultiPVNode(nodes1[i].getListe(),
                                        nodes1[i].getDescription(), nodes1[i].getId(),
                                        this);
            add(crown1[i]);
        }

        MultiPVGraph.MultiPVGraphNode[] nodes2 = gd.getMultiPVSortedSecondCrown();
        crown2 = new MultiPVNode[nodes2.length];
        for (int i = 0; i < crown2.length; i++) {
            crown2[i] = new MultiPVNode(nodes2[i].getListe(),
                                        nodes2[i].getDescription(),
                                        nodes2[i].getId(), this);
            add(crown2[i]);
        }

        // Creating the number nodes and links

        Vector num = new Vector();
        Vector lin = new Vector();
        for (int i = 0; i < nodes1.length; i++) {
            if (nodes1[i].getRelationsCount() > 0) {
                NumberNode node = new NumberNode(nodes1[i].getId(),
                                                 nodes1[i].getRelationsCount());
                NumberLink link = new NumberLink(crown1[i], node);
                num.addElement(node);
                lin.addElement(link);
                add(node);
                add(link);
            }
        }
        for (int i = 0; i < nodes2.length; i++) {
            if (nodes2[i].getRelationsCount() > 0) {
                NumberNode node = new NumberNode(nodes2[i].getId(),
                                                 nodes2[i].getRelationsCount());
                NumberLink link = new NumberLink(crown2[i], node);
                num.addElement(node);
                lin.addElement(link);
                add(node);
                add(link);
            }
        }
        numbers = new NumberNode[num.size()];
        num.toArray(numbers);
        nLinks = new NumberLink[lin.size()];
        lin.toArray(nLinks);

        // Creating Links from the Graph.GraphLinks of the Graph

        MultiPVGraph.MultiPVGraphLink[] llinks = gd.getMultiPVLinks();
        links = new MultiPVLink[llinks.length];
        int it = 0;
        for (int i = 0; i < links.length; i++) {
            links[i] = new MultiPVLink(new MultiPVNode(new ListeSynonymes("", ""),
                    "", 0, this),
                                       new MultiPVNode(new ListeSynonymes("", ""),
                    "", 0, this),
                                       /*new ListeSynonymes(""),*/
                                       Charte.getMiscellaneous());
            MultiPVNode node1 = null;
            MultiPVNode node2 = null;

            int from = llinks[i].getIdConcept1();
            int to = llinks[i].getIdConcept2();

            if (from >= MultiPVGraph.MultiPVGraphNode.MIN_ACTIVE &&
                from <= MultiPVGraph.MultiPVGraphNode.MAX_ACTIVE) {
                node1 = (MultiPVNode) activeNode;
            }
            if (to >= MultiPVGraph.MultiPVGraphNode.MIN_ACTIVE &&
                to <= MultiPVGraph.MultiPVGraphNode.MAX_ACTIVE) {
                node2 = (MultiPVNode) activeNode;
            }
            if (from >= MultiPVGraph.MultiPVGraphNode.MIN_CROWN1 &&
                from <= MultiPVGraph.MultiPVGraphNode.MAX_CROWN1) {
                for (int j = 0; j < crown1.length; j++) {
                    if (crown1[j].getId() == from) {
                        node1 = (MultiPVNode) crown1[j];
                    }
                }
            }
            if (to >= MultiPVGraph.MultiPVGraphNode.MIN_CROWN1 &&
                to <= MultiPVGraph.MultiPVGraphNode.MAX_CROWN1) {
                for (int j = 0; j < crown1.length; j++) {
                    if (crown1[j].getId() == to) {
                        node2 = (MultiPVNode) crown1[j];
                    }
                }
            }
            if (from >= MultiPVGraph.MultiPVGraphNode.MIN_CROWN2 &&
                from <= MultiPVGraph.MultiPVGraphNode.MAX_CROWN2) {
                for (int j = 0; j < crown2.length; j++) {
                    if (crown2[j].getId() == from) {
                        node1 = (MultiPVNode) crown2[j];
                    }
                }
            }
            if (to >= MultiPVGraph.MultiPVGraphNode.MIN_CROWN2 &&
                to <= MultiPVGraph.MultiPVGraphNode.MAX_CROWN2) {
                for (int j = 0; j < crown2.length; j++) {
                    if (crown2[j].getId() == to) {
                        node2 = (MultiPVNode) crown2[j];
                    }
                }
            }
            if (node1 != null && node2 != null) {
                links[i] = new MultiPVLink(node1, node2, /*llinks[i].getListe(),*/
                                           llinks[i].getColor());
                add(links[i]);
            } else {
                /*System.out.println("warning : null node in link : " + node1 +
                                   ", " +
                                   node2);*/
            }
            scrollRectToVisible(new Rectangle(0, 0, 10, 10));
        }

        // Creating ArrowComponents for the Links

        arrows = new LinkFactory.ArrowComponent[links.length];
        LinkFactory factory = new LinkFactory();
        for (int i = 0; i < arrows.length; i++) {
            int x1 = links[i].getNode1().getLocation().x;
            int y1 = links[i].getNode1().getLocation().y;
            int x2 = links[i].getNode2().getLocation().x;
            int y2 = links[i].getNode2().getLocation().y;
            String text = " " + links[i].getText() + " ";

            arrows[i] = factory.createArrowComponent(text,
                    factory.createArrow(x1, y1, x2,
                                        y2),
                    links[i].getColor(),
                    this);
            //add(arrows[i]);
        }
        processing = false;
    }

    class MultiPVNode extends Node {
        private JLabel[] contenu;

        public MultiPVNode(ListeSynonymes name, String description, int id,
                           GraphPanel parent) {
            super("", description, id, parent);
            this.removeAll();
            setLayout(new GridLayout(name.getListe().length, 1));
            JPanel[] pMots = new JPanel[name.getListe().length];
            contenu = new JLabel[name.getListe().length];
            for(int i=0; i<pMots.length; i++){
                pMots[i] = new JPanel(new BorderLayout());
                Charte.formate(pMots[i]);
                pMots[i].add(legende.getClasseur(name.getListe()[i].getConcernes()), BorderLayout.WEST);

                Image image = null;
                String son = "";
                String name0 = name.getListe()[i].getTexte();
                contenu[i] = new JLabel() {
                    public Dimension getPreferredSize(){
                        Dimension d = super.getPreferredSize();
                        int x = 1;
                        if(d.width>200){
                            x += d.width/200;
                        }
                        int h = (int)(1.8*x*getFont().getSize());
                        return new Dimension(d.width/x, x>1?h:d.height);
                    }
                };
                if (name0.endsWith("jpg") || name0.endsWith("gif") ||
                    name0.endsWith("png")) {
                    try {
                        URI uri = new URI(name0).normalize();
                        if (uri.getScheme().startsWith("file")) {
                            image = new ImageIcon(
                                    new File(uri).getAbsolutePath()).getImage();
                            if (image.getWidth(this) > 100 ||
                                image.getHeight(this) > 50) {
                                image = image.getScaledInstance(
                                        100, 50, Image.SCALE_SMOOTH);
                            }
                        } else if (uri.getScheme().startsWith("http")) {
                            image = new ImageIcon(uri.toURL()).getImage();
                            if (image.getWidth(this) > 100 ||
                                image.getHeight(this) > 50) {
                                image = image.getScaledInstance(
                                        100, 50, Image.SCALE_SMOOTH);
                            }
                        } else {
                            image = null;
                        }
                    } catch (NullPointerException npe) { // pas de Scheme comme file:, http:
                        image = null;
                    } catch (URISyntaxException use) { // URI incorrecte
                        image = null;
                    } catch (MalformedURLException mue) { // Trensformation en URL ratée
                        image = null;
                    }
                } else if (name0.endsWith("au") || name0.endsWith("mid") ||
                           name0.endsWith("wav")) {
                    try {
                        URI uri = new URI(name0).normalize();
                        if (uri.getScheme().startsWith("file")) {
                            son = new File(uri).getAbsolutePath();
                        } else if (uri.getScheme().startsWith("http")) {
                            son = uri.toURL().toString();
                        } else {
                            son = "";
                        }
                    } catch (NullPointerException npe) { // pas de Scheme comme file:, http:
                        son = "";
                    } catch (URISyntaxException use) { // URI incorrecte
                        son = "";
                    } catch (MalformedURLException mue) { // Transformation en URL ratée
                        son = "";
                    }
                }
                if (image != null) {
                    contenu[i].setIcon(new ImageIcon(image));
                } else if (!(son.equals(""))) {
                    contenu[i].setIcon(Charte.getIconeSon());
                } else {
                    contenu[i].setText("<html>"+name0);
                }
                Charte.formate(contenu[i]);
                pMots[i].add(contenu[i], BorderLayout.CENTER);
                add(pMots[i]);
            }
            setCursor(new Cursor(Cursor.HAND_CURSOR));
            addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent me) {
                    layout.setActive(false);
                }

                public void mouseReleased(MouseEvent me) {
                    layout.setActive(true);
                }
            });
            addMouseMotionListener(new MouseMotionAdapter() {
                public void mouseDragged(MouseEvent me) {
                    translate(me.getX() -
                              ((Component)(me.getSource())).getSize().width / 2,
                              me.getY() -
                              ((Component)(me.getSource())).getSize().height / 2);
                }
            });
        }

        protected void translate(int px, int py) {
            int x1 = getLocation().x + px;
            int y1 = getLocation().y + py;
            setLocation(x1, y1);
            for(int i=0; i<crown1.length; i++){
                if(isInCrownOf(this, crown1[i])){
                    crown1[i].translate2(px, py);
                }
            }
            for(int i=0; i<crown2.length; i++){
                if(isInCrownOf(this, crown2[i])){
                    crown2[i].translate2(px, py);
                }
            }
        }

        protected void translate2(int px, int py) {
            int x1 = getLocation().x + px;
            int y1 = getLocation().y + py;
            setLocation(x1, y1);
        }


        public void setFontSize(int fontSize) {
            for(int i=0; i<contenu.length; i++){
                contenu[i].setFont(getFont().deriveFont((float) fontSize));
            }
        }

        public void setBold() {
            for(int i=0; i<contenu.length; i++){
                contenu[i].setFont(getFont().deriveFont(Font.BOLD));
            }
        }
    }


    protected class MultiPVLink extends Link {

        public MultiPVLink(MultiPVNode node1, MultiPVNode node2, Color color) {
            super(node1, node2, "", color);
        }

        public String getText() {
            String s = "";
            return s;
        }

    }
}
