package data;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.File;
import java.util.ArrayList;

/**
 * Created by Bart.
 * Class to store top-level properties of a scripting project.
 */
@XmlRootElement(name = "scriptingProject")
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
@Log4j2
public class ScriptingProject {
    
    // Name of this project
    @Getter @Setter
    private String name;

    // Description of this project
    @Getter @Setter
    private String description;

    // List of cameras that are available in this project
    @Getter @Setter
    @XmlElementWrapper(name = "cameraList")
    @XmlElement(name = "camera")
    private ArrayList<Camera> cameras;

    // The director timeline of this project
    @Getter @Setter
    private DirectorTimeline directorTimeline;

    // The camera centerarea of this project
    @Getter @Setter
    @XmlElementWrapper(name = "camera-centerarea")
    @XmlElement(name = "cameraTimeline")
    private ArrayList<CameraTimeline> cameraTimelines;

    // The number of seconds per count;
    @Getter @Setter
    private double secondsPerCount;
    
    @Getter @Setter
    private String filePath;
    
    /**
     * Default constructor.
     */
    public ScriptingProject() {
        this("", 0);
    }

    /**
     * Constructor.
     * @param description - the description of the project
     * @param secondsPerCount - the number of seconds each count takes
     */
    public ScriptingProject(String description, double secondsPerCount) {
        log.debug("Initializing new ScriptingProject(description={}, secondsPerCount={})",
            description, secondsPerCount);

        this.description = description;
        this.secondsPerCount = secondsPerCount;
        this.cameras = new ArrayList<Camera>();
        this.cameraTimelines = new ArrayList<CameraTimeline>();
        this.directorTimeline = new DirectorTimeline(description, this);
    }
    
    /**
     * Constructor with name variable.
     * @param name the name of the project
     * @param description the description of the project
     * @param secondsPerCount the seconds per count in this project
     */
    public ScriptingProject(String name, String description, double secondsPerCount) {
        this(description, secondsPerCount);
        this.name = name;
    }

    /**
     * Method to write the current project to a file.
     * @param fileName  - the file to write the project to
     * @return          - boolean indicating if the write was successful
     */
    public boolean write(String fileName) {
        File file = new File(fileName);
        return write(file);
    }
    
    public boolean write() {
        return write(new File(filePath));
    }
    
    /**
     * Write the current project to file.
     * @param file the file to write to
     * @return true if write succeeded, false otherwise
     */
    public boolean write(File file) {
        log.info("Writing ScriptingProject to file {}", file.getAbsolutePath());
        try {
            JAXBContext context = JAXBContext.newInstance(ScriptingProject.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            m.marshal(this, file);
            return true;
        } catch (JAXBException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * Method to write the current project to a file.
     * @param fileName  - the file to write the project to
     * @return          - boolean indicating if the write was successful
     */
    public static ScriptingProject read(String fileName) {
        File file = new File(fileName);
        return read(file);
        
    }
    
    /**
     * Read a project from file.
     * @param file the file to read from
     * @return null if read failed, the read project otherwise
     */
    public static ScriptingProject read(File file) {
        log.info("Reading ScriptingProject from file {}", file.getAbsolutePath());
        try {
            JAXBContext context = JAXBContext.newInstance(ScriptingProject.class);
            Unmarshaller um = context.createUnmarshaller();
            ScriptingProject result =  (ScriptingProject) um.unmarshal(file);
            result.getDirectorTimeline().setProject(result);
            result.getCameraTimelines().forEach(e -> e.setProject(result));
            return result;
        } catch (JAXBException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Compute the number of counts from the number of seconds.
     * @param seconds - the number of seconds to compute with
     * @return - the computed number of counts
     */
    public double secondsToCounts(double seconds) {
        return seconds / secondsPerCount;
    }

    /**
     * Compute the number of seconds from the number of counts.
     * @param counts - the number of counts
     * @return - the computed number of seconds
     */
    public double countsToSeconds(double counts) {
        return counts * secondsPerCount;
    }

    /**
     * Add a camera to the project.
     * @param camera - the camera to add
     */
    public void addCamera(Camera camera) {
        cameras.add(camera);
    }

    /**
     * Add a camera timeline to the project.
     * @param cameraTimeline - the cameraTimeline to add
     */
    public void addCameraTimeline(CameraTimeline cameraTimeline) {
        cameraTimeline.setProject(this);
        cameraTimelines.add(cameraTimeline);
    }
}

@@ -1609,32 +1609,86 @@
 ePath;%0A    %0A
+    @Getter @Setter%0A    private boolean changed;%0A    %0A
     /**%0A
      * Defau
@@ -1671,24 +1671,24 @@
    %0A    /**%0A
-
      * Defau
@@ -2415,24 +2415,53 @@
 ion, this);%0A
+        this.changed = true;%0A
     %7D%0A    %0A 
@@ -2838,32 +2838,312 @@
  = name;%0A    %7D%0A%0A
+    %0A    /**%0A     * Project changed -%3E set changed variable to true.%0A     */%0A    public void changed() %7B%0A        this.changed = true;%0A    %7D%0A    %0A    /**%0A     * Changes saved -%3E reset changed variable.%0A     */%0A    public void saved() %7B%0A        this.changed = false;%0A    %7D%0A    %0A   %0A
     /**%0A     * M

Set up changed variable in scripting project