package CH.ifa.draw.util;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import de.renew.draw.storables.ontology.Drawing;
import de.renew.util.Scheduler;
import de.renew.util.StringUtil;


/**
 * The autosave task provides functionality to automatically save a drawing at a given interval.
 * The autosaving is started with the creation of the AutosaveTask and terminated
 * once the method <code>terminate()</code> is called or an error occurred.
 * @deprecated This class is not to be used externally and will later be hidden.
 */
@Deprecated(since = "5.0", forRemoval = true)
public class AutosaveTask implements Runnable {
    /**
     * Logger for the class AutosaveTask.
     * Only a single logger instance exists at any given time. If a logger for AutosaveTask
     * already exists it is returned or else a new instance is created.
     */
    public static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(AutosaveTask.class);
    private final Drawing _drawing;
    private long _lastSaved;
    private long _interval;

    /**
     * <code>autosaveFilename</code> is null, until the first
     * time that the drawing was saved. Afterward, it keeps track
     * of the name of the autosave file.
     */
    private File _autosaveFilename = null;
    private final AutosaveSaver _saver;

    /**
     * Construct a new AutosaveTask and starts the repeated autosaving process.
     *
     * @param saver the saver used to save drawings
     * @param drawing the drawing to be saved
     * @param interval the interval at which the drawing will be saved
     */
    public AutosaveTask(AutosaveSaver saver, Drawing drawing, long interval) {
        this._saver = saver;
        this._drawing = drawing;
        this._interval = interval;
        reset();

        Scheduler.instance().executeIn(this, interval);
    }

    private void touch(File filename) {
        try {
            FileOutputStream stream = new FileOutputStream(filename);
            stream.close();
        } catch (IOException e) {
            // Never try to save again.
            _interval = 0;
            LOGGER.debug("Autosave of drawing " + _drawing.getName() + " cancelled: " + e);
        }
    }

    /**
     * Set the last saved time to the current time.
     */
    public synchronized void reset() {
        _lastSaved = System.currentTimeMillis();
    }

    /**
     * Terminate the autosave process, removing the autosave file,
     * if it exists.
     */
    public synchronized void terminate() {
        _interval = 0;
        Scheduler.instance().cancel(this);
        if (_autosaveFilename != null) {
            if (_autosaveFilename.exists()) {
                LOGGER.debug("Deleting autosave copy " + _autosaveFilename + "...");
                boolean deleted = _autosaveFilename.delete();
                LOGGER.debug(
                    "Autosave copy " + _autosaveFilename
                        + (deleted ? " was deleted successfully." : " could not be deleted."));
            }
        }
    }

    @Override
    public synchronized void run() {
        if (_interval > 0) {
            // Ok, this autosave task is still associated to an
            // open drawing.
            long now = System.currentTimeMillis();
            long remainingDelay = _lastSaved + _interval - now;
            if (remainingDelay <= 0) {
                if (_drawing.isModified()) {
                    if (_autosaveFilename == null) {
                        File filename = _drawing.getFilename();
                        if (filename != null) {
                            _autosaveFilename = new File(
                                StringUtil.stripFilenameExtension(filename.getPath()) + ".aut");
                        }
                        if (_autosaveFilename != null && !_autosaveFilename.exists()) {
                            touch(_autosaveFilename);
                        } else {
                            _autosaveFilename = null;
                            for (int i = 0; i < 25 && _autosaveFilename == null
                                && _interval > 0; i++) {
                                int autosaveNumber = (int) Math.floor(Math.random() * 100000);
                                File testFilename = new File("rnw" + autosaveNumber + ".aut");
                                try {
                                    if (testFilename.createNewFile()) {
                                        // Remember the filename.
                                        _autosaveFilename = testFilename;
                                    }
                                } catch (IOException e) {
                                    // An error occurred. Do not save again.
                                    _interval = 0;
                                    LOGGER.debug(
                                        "Autosave of drawing " + _drawing.getName() + " cancelled: "
                                            + e);
                                }
                            }
                        }
                    }

                    if ((_interval > 0) && _autosaveFilename != null) {
                        Rectangle rect = _drawing.displayBox();
                        Dimension size =
                            new Dimension(rect.width + rect.x + 200, rect.height + rect.y + 200);
                        try {
                            LOGGER.debug(
                                "Autosaving drawing " + _drawing.getName() + " to "
                                    + _autosaveFilename + "...");
                            _saver.saveAutosaveFile(_drawing, _autosaveFilename, new Point(), size);
                        } catch (IOException e) {
                            // An error occurred. Do not save again.
                            _interval = 0;
                            LOGGER.debug(
                                "Autosave of drawing " + _drawing.getName() + " cancelled: " + e);
                        }
                    }
                }


                // We just tried to save. Reset the clock.
                reset();
            }
            if (_interval > 0) {
                // Another save is desired.
                Scheduler.instance().executeAt(this, _lastSaved + _interval);
            }
        }
    }
}