package com.framsticks.net.client3D;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.io.File;
import java.io.FilenameFilter;
import java.util.HashMap;
import java.util.Set;

import javax.media.opengl.GLCanvas;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * Okno z widokiem OpenGL w ktorym wszystko jest renderowane
 * @author vorg
 *
 */
public class Viewer extends JPanel implements MouseListener, MouseMotionListener  {
	static final long serialVersionUID = 1;
	private Renderer renderer;
	private HashMap<String, cgfxEffect> styles;
	private Creature[] creatures;
	private int clickX;
	private int clickY;
	private float clickRotY;
	private float clickRotX;
	private App app = null;
	
	public Viewer(App app) {
		this.app = app;
		init();
	}
	
	public Viewer(){
		init();
	}
	
	public JFrame showInFrame(){
		JFrame frame = new JFrame("Framsticks - Client3D");
		JFrame.setDefaultLookAndFeelDecorated(true);
		frame.setSize(500, 500);
		if(app != null){
			frame.setLocationRelativeTo(app);
			frame.setLocation(app.getX()-frame.getSize().width, app.getY());
		}
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		Container contentPane = frame.getContentPane();
		contentPane.setLayout(new BorderLayout());
		contentPane.add(this, BorderLayout.CENTER);
		return frame;
	}
	
	private void init() {
		styles = new HashMap<String, cgfxEffect>();
		createCanvas();

		MouseWheelListener listener = new MouseWheelListener() {
		
//			float zoomFactor = 0.1f;
			public void mouseWheelMoved(MouseWheelEvent e) {
			renderer.setTranslation(renderer.getTranslation() * (float)(e.getWheelRotation() * 0.1 + 1.0) );
			}
		};
		this.addMouseWheelListener(listener);
//		Log.getInstance().addLoggerListener(new ILogListener() {
//			public void onMesssage(String category, String text) {
//				System.out.println(category + " > " + text );
//			}
//		});
		
	}

	/**
	 * Tworzenie powierzchni do renderowania OpenGL'a
	 *
	 */
	private void createCanvas() {
		GLCanvas canvas = new GLCanvas();
		//GLJPanel canvas = new GLJPanel(); 
		renderer = new Renderer();
		
		
		canvas.addGLEventListener(renderer);
		canvas.addMouseListener(this);
		canvas.addMouseMotionListener(this);
		
		canvas.setVisible(true);	
		
		this.setOpaque(true);
		
		this.setLayout(new BorderLayout());
		this.add(canvas, BorderLayout.CENTER);
		this.setVisible(true);
		
		File dir = new File("res/shaders");
	    
	    
	    
	    
	    // It is also possible to filter the list of returned files.
	    // This example does not return any files that start with `.'.
	    FilenameFilter filter = new FilenameFilter() {
	        public boolean accept(File dir, String name) {
	        
	            return name.matches(".*[cC][gG][fF][xX]$");
	        }
	    };
	    String[] children = dir.list(filter);
	    dir = new File("../..");
	    for (int i=0; i<children.length; i++)
	    {
	    	String name = children[i].substring(0,children[i].length()-5);
	    	cgfxEffect effect = new cgfxEffect(name);
	    	
	    	styles.put(name, effect);
	    	if(app != null){
	    		app.AddStyle(name);
	    	}
	    	//effect.LoadByName(name, context)
	    	//children[i];
	    	
	    	Log.getInstance().log("dbg",name);
	    }
	    setStyle("default");
		//styles.put("basic", new BasicStyle());	
		//styles.put("fur", new FurStyle());
		//styles.put("stone", new StoneStyle());
		
		//setStyle("basic");
	}
	
	public void setCreatures(Creature[] creatures) {
		this.creatures = creatures;
		renderer.setCreatures(creatures);
	}
	
	public void setWorld(World world) {
		renderer.setWorld(world);
	}

	public Set<String> getStyleNames(){
		return styles.keySet();
	}
	
	public void setStyle(String styleName) {
		if (styles.containsKey(styleName)) {
			renderer.setStyle(styles.get(styleName));
		}
		else {
			Log.getInstance().log("wrn", "Style: "+styleName+" not found");
			Log.getInstance().log("dbg", "Available styles:");
			for(String key : styles.keySet()) {
				Log.getInstance().log("dbg", key);
			}
		}
	}
	
	/**
	 * Przelacza widok na stwora z grupy 'group' o indeksie 'index'
	 * Podanie obu parametrow z wartoscia -1 wlacza z powrotem widok calego swiata
	 * @param group
	 * @param index
	 */
	public void setView(int group, int index) {
		if (creatures == null) {
			return;
		}
		renderer.resetTranslation();
		if ((group == -1) || (index == -1)) {
			//if ((creatures != null) && creatures.length > 0)
			renderer.setCreatures(creatures);
			renderer.setModelType(Creature.ModelType.MechParts);
		}
		else {
			Creature creature = null;
			for(Creature c : creatures) {
				if ((c.getGroup() == group) && (c.getIndex() == index)) {
					creature = c;
					break;
				}
			}
			if (creature != null) {
				renderer.setCreatures(new Creature[] { creature });
				renderer.setModelType(Creature.ModelType.Parts);
			}
			else {
				renderer.setCreatures(creatures);
				renderer.setModelType(Creature.ModelType.MechParts);
			}
		
		}
	}
	
	public void mouseClicked(MouseEvent e) { }
	public void mouseEntered(MouseEvent e) { }
	public void mouseExited(MouseEvent e) { }

	public void mousePressed(MouseEvent e) {
		//Log.getInstance().log("dbg", "Mouse Down");
		clickX = e.getX();
		clickY = e.getY();
		clickRotY = renderer.getRotationY();
		clickRotX = renderer.getRotationX();
	}

	public void mouseReleased(MouseEvent e) {
		//Log.getInstance().log("dbg", "Mouse Up");
	}

	public void mouseDragged(MouseEvent e) { 
		float difX = (e.getX()-clickX)/(float)getWidth();
		float difY = (e.getY()-clickY)/(float)getHeight();
		renderer.setRotationY(clickRotY + 180*difX);
		renderer.setRotationX(clickRotX + 180*difY);
	}

	public void mouseMoved(MouseEvent e) { }

	
	
	
	
}