package entities;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.joml.Vector4f;

import graphical.Material;
import graphical.Texture;
import md5.MD5AnimModel;
import md5.MD5Loader;
import md5.MD5Model;
import obj.OBJLoader;

public class EntityStore {
	
	private HashMap<String,EntityData> entities = new HashMap<String,EntityData>();
	
	public EntityStore(){}
	
	public void init(){
		String entityRoot = "data/entities/";
		String[] enTypes = getSubDirectoriesInFolder(entityRoot);
		for (String s : enTypes){
			String entityFolder = entityRoot+s+"/";
			loadEntityTypeData(s,entityFolder);
		}
	}
	
	private void loadEntityTypeData(String type, String entityFolder) {
		String[] entities = getSubDirectoriesInFolder(entityFolder);
		for (String subType : entities){
			try {
				loadEntity(type,subType);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private void loadEntity(String type, String subType) throws Exception {
		String entityPath = "data/entities/"+type+"/"+subType+"/";
		
		EntityData ed = new EntityData();
		ed.type = type;
		ed.subType = subType;
		
		loadEntityDataFile(ed,entityPath);
		
		if (!ed.isAnimated){
			if (new File(entityPath+"model.obj").exists()){
				if (new File(entityPath+"texture.png").exists()){
						ed.mesh = OBJLoader.loadMesh(entityPath+"model.obj");
						ed.mesh.setTransparency(ed.hasTransparency);
						Texture texture = new Texture(entityPath+"texture.png",ed.textureAtlasRowCount,ed.textureAtlasRowCount);
						ed.mesh.setMaterial(new Material(texture, ed.reflectance));
						if (ed.normalMap!=null){
							ed.mesh.getMaterial().setNormalMap(new Texture(entityPath+ed.normalMap+".png"));
						}
					this.entities.put(ed.type+"."+ed.subType,ed);
				}else{
					System.err.println("Missing Texture @ "+type+"."+subType);
				}
			}else{
				System.err.println("Missing Model @ "+type+"."+subType);
			}
		}else{
			if (new File(entityPath+"mesh.md5mesh").exists()){
				ed.md5MeshModel = MD5Model.parse(entityPath+"mesh.md5mesh");
				if (new File(entityPath+"anim.md5anim").exists()){
			        ed.md5AnimModel = MD5AnimModel.parse(entityPath+"anim.md5anim");
			        this.entities.put(ed.type+"."+ed.subType,ed);
				}else{
					System.err.println("Missing anim file @ "+type+"."+subType);
				}
			}else{
				System.err.println("Missing mesh file @ "+type+"."+subType);
			}
		}

		

	}

	private void loadEntityDataFile(EntityData ed,String path) throws IOException {
		
		if (new File(path+"data.txt").exists()){
			BufferedReader br = new BufferedReader(new FileReader(path+"data.txt"));
			String contentLine = "";
			while ((contentLine=br.readLine()) != null) {
		        String varible = contentLine.split("=")[0];
		        String data = contentLine.split("=")[1];
		        switch(varible){
			        case "textureAtlasRowCount":{
			        	ed.textureAtlasRowCount = Integer.parseInt(data);
			        	break;
			        }
			        case "hasTransparency":{
			        	ed.hasTransparency = Boolean.parseBoolean(data);
			        	break;
			        }
			        case "reflectance":{
			        	ed.reflectance = Float.parseFloat(data);
			        	break;
			        }
			        case "normalMap":{
			        	ed.normalMap = data;
			        	break;
			        }
			        case "isAnimated":{
			        	ed.isAnimated = Boolean.parseBoolean(data);
			        	break;
			        }
			        case "tag":{
			        	ed.tags.add(data);
			        	break;
			        }
			        default:{
			        	System.err.println("Parsing "+ed.type+"."+ed.subType +" failed; Unknown varible "+varible);
			        }
		        }
		    }
			br.close();
		}
	}

	public String[] getSubDirectoriesInFolder(String path){
		File file = new File(path);
		String[] directories = file.list(new FilenameFilter() {
		  @Override
		  public boolean accept(File current, String name) {
			  return new File(current, name).isDirectory();
		  }
		});
		return directories;
	}

	public ArrayList<String> getTypes() {
		ArrayList<String> types = new ArrayList<>();
		for (EntityData ed : entities.values()){
			if (types.indexOf(ed.type)==-1){
				types.add(ed.type);
			}
		}
		return types;
	}

	public ArrayList<String> getSubType(String s) {
		ArrayList<String> types = new ArrayList<>();
		for (EntityData ed : entities.values()){
			if(ed.type.equals(s)){
				if (types.indexOf(ed.subType)==-1){
					types.add(ed.subType);
				}
			}
		}
		return types;
	}
	
	public EntityData getData(String key){
		return this.entities.get(key);
	}
	
	public Entity newEntity(String key) throws Exception{
		EntityData ed = this.entities.get(key);
		Entity returnEntity = null;
		if (ed!=null){
			if (!ed.isAnimated){
				returnEntity = new Entity(ed);
			}else{
				returnEntity = MD5Loader.process(ed, new Vector4f(1, 1, 1, 1));
			}
		}else{
			System.err.println("Entity "+ key +" not found.");
		}
		return returnEntity;
	}
}
