package com.clearlyspam23.GLE.level;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.FilenameUtils;
import com.clearlyspam23.GLE.Nameable;
import com.clearlyspam23.GLE.PropertyTemplate;
import com.clearlyspam23.GLE.Template;
import com.clearlyspam23.GLE.GUI.EditActionListener;
import com.clearlyspam23.GLE.edit.EditAction;
import com.clearlyspam23.GLE.exception.TemplateMismatchException;
import com.clearlyspam23.GLE.util.Vector2;
public class Level implements Nameable, EditActionListener{
private Template template;
@SuppressWarnings("rawtypes")
private List<Layer> layers = new ArrayList<Layer>();
private List<LevelChangeListener> listeners = new ArrayList<LevelChangeListener>();
private List<EditActionListener> editListeners = new ArrayList<EditActionListener>();
private List<EditAction> undoStack = new ArrayList<EditAction>();
private List<EditAction> redoStack = new ArrayList<EditAction>();
private int editCount;
private Vector2 dimensions = new Vector2();
private LinkedHashMap<String, Object> properties = new LinkedHashMap<String, Object>();
private File saveFile;
@SuppressWarnings("rawtypes")
public Level(Template template)
{
this.template = template;
for(LayerTemplate t : template.getLayers()){
addLayer(t.createLayer());
}
for(PropertyTemplate t : template.getActiveProperties()){
Object o = t.getDefaultValue();
properties.put(t.getName(), o);
}
}
/**
* constructs a Level from the given Template and LevelData.
* Will also attempt to validate the LevelData with this template, and may throw an exception if the two are not compatible
* @param template
* @param data
* @throws TemplateMismatchException
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public Level(Template template, LevelData data) throws TemplateMismatchException{
this.template = template;
for(LayerData d : data.layers){
LayerTemplate t = template.getLayerTemplate(d.getName());
if(t==null)
throw new TemplateMismatchException(template, this, false, d.getName());
try{
Layer l = t.createLayer();
l.buildFromData(d.data);
addLayer(l);
}
catch(Exception e){
throw new TemplateMismatchException(template, this, false, d.getName(), e);
}
}
for(Entry<String, Object> e : data.properties.entrySet()){
PropertyTemplate t = template.getPropertyTemplate(e.getKey());
if(t==null)
throw new TemplateMismatchException(template, this, true, e.getKey());
try{
// Layer l = t.createLayer();
// l.buildFromData(d);
// layers.add(l);
}
catch(Exception exc){
throw new TemplateMismatchException(template, this, false, e.getKey(), exc);
}
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void setToData(LevelData data) throws TemplateMismatchException{
setDimensions(data.width, data.height);
for(int i = 0; i < layers.size(); i++){
try{
Layer l = layers.get(i);
l.onResize(this, dimensions.x, dimensions.y);
l.buildFromData(data.layers[i].data);
}
catch(Exception e){
throw new TemplateMismatchException(template, this, false, data.layers[i].getName(), e);
}
}
for(Entry<String, Object> e : data.properties.entrySet()){
PropertyTemplate t = template.getPropertyTemplate(e.getKey());
if(t==null)
throw new TemplateMismatchException(template, this, true, e.getKey());
try{
properties.put(e.getKey(), e.getValue());
}
catch(Exception exc){
throw new TemplateMismatchException(template, this, false, e.getKey(), exc);
}
}
}
public boolean needsSave(){
return editCount!=0;
}
@Override
public void actionMade(EditAction data){
undoStack.add(data);
redoStack.clear();
editCount++;
for(EditActionListener l : editListeners){
l.actionMade(data);
}
}
public boolean canUndo(){
return !undoStack.isEmpty();
}
public boolean undoAction(){
if(canUndo()){
EditAction e = undoStack.remove(undoStack.size()-1);
e.undoAction();
redoStack.add(e);
editCount--;
for(EditActionListener l : editListeners){
l.actionMade(e);
}
return true;
}
return false;
}
public EditAction getTopUndo(){
return undoStack.get(undoStack.size()-1);
}
public boolean canRedo(){
return !redoStack.isEmpty();
}
public boolean redoAction(){
if(canRedo()){
EditAction e = redoStack.remove(redoStack.size()-1);
e.doAction();
undoStack.add(e);
editCount++;
for(EditActionListener l : editListeners){
l.actionMade(e);
}
return true;
}
return false;
}
public EditAction getTopRedo(){
return redoStack.get(redoStack.size()-1);
}
public void acknowledgeSave(){
editCount = 0;
}
public void setDimensions(double width, double height){
dimensions.set(width, height);
for(LevelChangeListener l : listeners){
l.onResize(this, width, height);
}
}
public double getWidth(){
return dimensions.x;
}
public double getHeight(){
return dimensions.y;
}
public Vector2 getDimensions(){
return dimensions.copy();
}
public Template getTemplate() {
return template;
}
public void setTemplate(Template template) {
this.template = template;
}
@SuppressWarnings("rawtypes")
public void addLayer(Layer l)
{
layers.add(l);
listeners.add(l);
}
@SuppressWarnings("rawtypes")
public List<Layer> getLayers()
{
return Collections.unmodifiableList(layers);
}
public LevelData generateLevelData(){
LevelData data = new LevelData();
data.width = dimensions.x;
data.height = dimensions.y;
data.layers = new LayerData[layers.size()];
for(int i = 0; i < layers.size(); i++){
data.layers[i] = new LayerData(layers.get(i).getName(), layers.get(i).getExportData());
}
for(Entry<String, Object> p : properties.entrySet()){
data.properties.put(p.getKey(), p.getValue());
}
return data;
}
public Map<String, Object> getProperties(){
return properties;
}
public void setProperty(String name, Object property){
properties.put(name, property);
}
@Override
public String getName() {
return saveFile!=null ? FilenameUtils.removeExtension(saveFile.getName()) : "New Level";
}
public File getSaveFile() {
return saveFile;
}
public void setSaveFile(File saveFile) {
this.saveFile = saveFile;
}
public void addChangeListener(LevelChangeListener listener){
listeners.add(listener);
}
public void removeChangeListener(LevelChangeListener listener){
listeners.remove(listener);
}
public void addEditActionListener(EditActionListener listener){
editListeners.add(listener);
}
public void removeEditActionListener(EditActionListener listener){
editListeners.remove(listener);
}
@Override
public void cutAvailabilityChange(boolean isAvailable) {
for(EditActionListener l : editListeners)
l.cutAvailabilityChange(isAvailable);
}
@Override
public void copyAvailabilityChange(boolean isAvailable) {
for(EditActionListener l : editListeners)
l.copyAvailabilityChange(isAvailable);
}
@Override
public void pasteAvailabilityChange(boolean isAvailable) {
for(EditActionListener l : editListeners)
l.pasteAvailabilityChange(isAvailable);
}
}