/*
 * Copyright 2007 nori090
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lib2chj;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.HeadlessException;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.swing.AbstractListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.JTree.DynamicUtilTreeNode;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import lib2chj.struct.Category;
import lib2chj.struct.Comment;
import lib2chj.struct.Ita;
import lib2chj.struct.Server;
import lib2chj.struct.Subject;
import lib2chj.util.BbsMenu;
import lib2chj.util.ParseUtil;
import lib2chj.util.SubjectBuilder;
import lib2chj.util.ThreadBuilder;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

/**
 * swingで簡易2chブラウザ
 * 
 * @author nori090
 * @version $Rev: 19 $ $Date: 2008-03-25 22:46:11 +0900 (Tue, 25 Mar 2008) $
 */
public class SimpleGUI
    extends JFrame {
    VelocityContext context = new VelocityContext();

    Template template;
    {
        try {
            Properties p = new Properties();
            p.load( this.getClass().getClassLoader().getResourceAsStream( "lib2chj/velocity.properties" ) );
            Velocity.init( p );
            template = Velocity.getTemplate( "lib2chj/thread_layout.vm", "UTF-8" );
            context.put( "util", new ParseUtil() );
        }
        catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    private JTree menutree;

    private JList subjectlist;

    private JEditorPane commentarea;

    private Set<Category> menu = BbsMenu.getCategorys();

    private Subject[] subjects = new HashMap<String, Subject>().values().toArray( new Subject[] {} );

    private Comment[] comments = new HashMap<String, Comment>().values().toArray( new Comment[] {} );

    public static void main( String[] args ) {
        try {
            new SimpleGUI().setVisible( true );
        }
        catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    public SimpleGUI()
        throws HeadlessException, ClassNotFoundException, InstantiationException, IllegalAccessException,
        UnsupportedLookAndFeelException {
        super();
        UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
        menutree = new JTree( createMenuTree( menu ) ) {
            @Override
            public String convertValueToText( Object value, boolean selected, boolean expanded, boolean leaf, int row,
                                              boolean hasFocus ) {
                if ( value != null ) {
                    if ( value instanceof DefaultMutableTreeNode ) {
                        DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
                        Object text = null;
                        try {
                            Object target = node.getUserObject();
                            if ( !( target instanceof String ) ) {
                                Method m = target.getClass().getMethod( "view" );
                                text = m.invoke( target );
                            }
                        }
                        catch ( Exception e ) {
                            e.printStackTrace();
                        }
                        if ( text == null ) {
                            return ( value.toString() );
                        }
                        else {
                            return ( text.toString() );
                        }
                    }
                    else {
                        return value.toString();
                    }
                }
                else {
                    return "";
                }
            }
        };

        subjectlist = new JList( subjects );
        subjectlist.setCellRenderer( new MyListCellRenderer() );

        commentarea = new JEditorPane();
        commentarea.setEditable( false );
        commentarea.setContentType( "text/html" );

        subjectlist.setSelectionBackground( Color.BLUE );

        MouseListener menu_mouseListener = new MouseAdapter() {
            @Override
            public void mousePressed( MouseEvent e ) {
                if ( e.getClickCount() == 2 ) {
                    TreePath path = menutree.getPathForLocation( e.getX(), e.getY() );
                    if ( path != null ) {
                        Object o = path.getLastPathComponent();
                        if ( o instanceof DefaultMutableTreeNode ) {
                            DefaultMutableTreeNode node = (DefaultMutableTreeNode) o;
                            Object target = node.getUserObject();
                            if ( target instanceof Ita ) {
                                Ita ita = (Ita) target;
                                try {
                                    Map<String, Server> map = new SubjectBuilder().get( ita.getUrl() ).toMap();
                                    String server = new URL( ita.getUrl() ).getHost();
                                    ita.setSubjects( ( ( map.get( server ) ).getIta( ita.getItaName() ) ).getSubjects() );
                                    subjects =
                                        ( ( map.get( server ) ).getIta( ita.getItaName() ) ).getSubjects().values().toArray(
                                                                                                                             new Subject[] {} );
                                }
                                catch ( IOException e1 ) {
                                    e1.printStackTrace();
                                }
                                subjectlist.setModel( new AbstractListModel() {
                                    public int getSize() {
                                        return subjects.length;
                                    }

                                    public Object getElementAt( int i ) {
                                        return subjects[i];
                                    }
                                } );
                            }
                        }
                    }
                }
            }
        };

        MouseListener mouseListener3 = new MouseAdapter() {
            @Override
            public void mouseClicked( MouseEvent e ) {
                if ( e.getClickCount() == 2 ) {
                    int index = subjectlist.locationToIndex( e.getPoint() );
                    Subject subject = (Subject) ( subjectlist.getModel().getElementAt( index ) );
                    if ( subject != null ) {
                        try {
                            Map<String, Server> map = new ThreadBuilder().get( subject.getThread().getUrl() ).toMap();
                            String server = new URL( subject.getUrl() ).getHost();
                            subject.setThread( map.get( server ).getIta( subject.getIta().getItaName() ).getThread(
                                                                                                                    subject.getId() ) );
                            comments =
                                map.get( server ).getIta( subject.getIta().getItaName() ).getThread( subject.getId() ).getComments().toArray(
                                                                                                                                              new Comment[] {} );
                        }
                        catch ( IOException e1 ) {
                            e1.printStackTrace();
                        }
                        commentarea.setText( create_html( new StringWriter(), comments ) );
                    }
                }
            }
        };

        menutree.addMouseListener( menu_mouseListener );
        subjectlist.addMouseListener( mouseListener3 );

        menutree.setFont( new Font( "Serif", Font.PLAIN, 12 ) );
        subjectlist.setFont( new Font( "Serif", Font.PLAIN, 12 ) );
        commentarea.setFont( new Font( "ＭＳ ゴシック", Font.PLAIN, 12 ) );

        this.add( menutree, BorderLayout.WEST );
        this.add( subjectlist, BorderLayout.NORTH );
        this.add( commentarea, BorderLayout.CENTER );

        JScrollPane scroll3 = new JScrollPane( subjectlist );
        this.add( scroll3, BorderLayout.NORTH );

        JScrollPane scroll5 = new JScrollPane( menutree );
        this.add( scroll5, BorderLayout.WEST );

        JScrollPane scroll6 = new JScrollPane( commentarea );
        this.add( scroll6, BorderLayout.CENTER );

        this.setSize( new Dimension( 800, 600 ) );
        this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        this.setTitle( "2ch Simple GUI" );
    }

    static TreeModel createMenuTree( Set<Category> menu ) {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode( "root" );
        for ( Category c : menu ) {
            DefaultMutableTreeNode category_node = new DefaultMutableTreeNode( c );
            DynamicUtilTreeNode.createChildren( category_node, c.getItaMap().values().toArray() );
            root.add( category_node );
        }
        return new DefaultTreeModel( root, false );
    }

    String create_html( StringWriter sw, Comment[] comments ) {
        try {
            context.put( "age", comments[0] );
            context.put( "comments", comments );

            template.merge( context, sw );
            return sw.toString();
        }
        catch ( Exception e ) {
            e.printStackTrace();
            return "";
        }
    }

    private static class MyListCellRenderer
        extends DefaultListCellRenderer {

        public MyListCellRenderer() {
            super();
        }

        @Override
        public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected,
                                                       boolean cellHasFocus ) {
            setComponentOrientation( list.getComponentOrientation() );

            Color bg = null;
            Color fg = null;

            JList.DropLocation dropLocation = list.getDropLocation();
            if ( dropLocation != null && !dropLocation.isInsert() && dropLocation.getIndex() == index ) {

                bg = UIManager.getColor( "List.dropCellBackground" );
                fg = UIManager.getColor( "List.dropCellForeground" );

                isSelected = true;
            }

            if ( isSelected ) {
                setBackground( bg == null ? list.getSelectionBackground() : bg );
                setForeground( fg == null ? list.getSelectionForeground() : fg );
            }
            else {
                setBackground( list.getBackground() );
                setForeground( list.getForeground() );
            }

            if ( value instanceof Icon ) {
                setIcon( (Icon) value );
                setText( "" );
            }
            else {
                setIcon( null );
                Object text = null;
                try {
                    Method m = value.getClass().getMethod( "view" );
                    text = m.invoke( value );
                }
                catch ( Exception e ) {
                    e.printStackTrace();
                }
                if ( text == null ) {
                    setText( ( value == null ) ? "" : value.toString() );
                }
                else {
                    setText( text.toString() );
                }

            }

            setEnabled( list.isEnabled() );
            setFont( list.getFont() );

            Border border = null;
            if ( cellHasFocus ) {
                if ( isSelected ) {
                    border = UIManager.getBorder( "List.focusSelectedCellHighlightBorder" );
                }
                if ( border == null ) {
                    border = UIManager.getBorder( "List.focusCellHighlightBorder" );
                }
            }
            else {
                border = getNoFocusBorder();
            }
            setBorder( border );

            return this;
        }

        private static final Border SAFE_NO_FOCUS_BORDER = new EmptyBorder( 1, 1, 1, 1 );

        private static Border getNoFocusBorder() {
            if ( System.getSecurityManager() != null ) {
                return SAFE_NO_FOCUS_BORDER;
            }
            else {
                return noFocusBorder;
            }
        }
    }
}
