package de.renew.draw.storables.impl.services;

import java.awt.Rectangle;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import java.util.function.Predicate;

import CH.ifa.draw.IOHelper;
import CH.ifa.draw.figures.ElbowTextLocator;
import CH.ifa.draw.framework.DrawingTypeManager;
import CH.ifa.draw.standard.FilteredFigureEnumerator;
import CH.ifa.draw.standard.MergedFigureEnumerator;
import CH.ifa.draw.standard.NullDrawing;
import CH.ifa.draw.standard.OffsetLocator;
import CH.ifa.draw.util.PatchingStorableInput;
import de.renew.draw.storables.api.services.StorableService;
import de.renew.draw.storables.impl.drawings.DrawingExportFormatHolder;
import de.renew.draw.storables.impl.drawings.DrawingImportFormatHolder;
import de.renew.draw.storables.impl.util.internal.StorableHelper;
import de.renew.draw.storables.ontology.Drawing;
import de.renew.draw.storables.ontology.DrawingChangeEvent;
import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.storables.ontology.FigureChangeEvent;
import de.renew.draw.storables.ontology.FigureEnumeration;
import de.renew.draw.storables.ontology.Locator;
import de.renew.draw.storables.ontology.Storable;
import de.renew.draw.storables.ontology.StorableInput;
import de.renew.draw.storables.ontology.StorableOutput;
import de.renew.ioontology.ExtensionFileFilter;
import de.renew.ioontology.MultiExtensionFileFilter;
import de.renew.ioontology.exporting.ExportFormat;
import de.renew.ioontology.importing.ImportFormat;

/**
 * Contains the storable functionalities for the storable service.
 *
 * @author Clara von Bargen
 */
public class StorableServiceImpl implements StorableService {

    @Override
    public StorableInput createStorableInput(InputStream stream) {
        return new CH.ifa.draw.util.StorableInput(stream);
    }

    @Override
    public StorableInput createStorableInput(InputStream stream, boolean useUTF8) {
        return new CH.ifa.draw.util.StorableInput(stream, useUTF8);
    }

    @Override
    public StorableInput createStorableInput(URL location, boolean useUTF8) throws IOException {
        return new CH.ifa.draw.util.StorableInput(location, useUTF8);
    }

    @Override
    public StorableInput createStorableInput(String string) {
        return new CH.ifa.draw.util.StorableInput(string);
    }

    @Override
    public StorableInput createPatchingStorableInput(InputStream stream) {
        return new PatchingStorableInput(stream, true);
    }

    @Override
    public StorableInput createPatchingStorableInput(URL location, boolean useUTF8)
        throws IOException
    {
        return new PatchingStorableInput(location, useUTF8);
    }

    @Override
    public StorableOutput createStorableOutput(File file) throws FileNotFoundException {
        return new CH.ifa.draw.util.StorableOutput(file);
    }

    @Override
    public StorableOutput createStorableOutput(OutputStream stream) {
        return new CH.ifa.draw.util.StorableOutput(stream);
    }

    @Override
    public <S extends Storable> S cloneStorable(S original) throws Exception {
        return StorableHelper.cloneStorable(original);
    }

    @Override
    public DrawingChangeEvent createDrawingChangeEvent(Drawing source, Rectangle r) {
        return new CH.ifa.draw.framework.DrawingChangeEvent(source, r);
    }

    @Override
    public FigureChangeEvent createFigureChangeEvent(Figure figure, Rectangle rectangle) {
        return new CH.ifa.draw.framework.FigureChangeEvent(figure, rectangle);
    }

    @Override
    public FigureChangeEvent createFigureChangeEvent(Figure figure) {
        return new CH.ifa.draw.framework.FigureChangeEvent(figure);
    }


    @Override
    public FigureEnumeration createFilteredFigureEnumerator(
        FigureEnumeration enumeration, Predicate<Figure> predicate)
    {
        return new FilteredFigureEnumerator(enumeration, figure -> predicate.test(figure));
    }

    @Override
    public FigureEnumeration createMergedFigureEnumerator(
        FigureEnumeration enumA, FigureEnumeration enumB)
    {
        return new MergedFigureEnumerator(enumA, enumB);
    }

    @Override
    public boolean isDrawingNullDrawing(Drawing drawing) {
        return drawing instanceof NullDrawing;
    }

    @Override
    public MultiExtensionFileFilter getKnownDrawingTypesFileFilter() {
        return IOHelper.getInstance().getFileFilterKnownTypes();
    }

    @Override
    public ExtensionFileFilter getExtensionFileFilterByDrawingType(String drawingType) {
        return DrawingTypeManager.getInstance().getFilter(drawingType);
    }

    @Override
    public void registerDrawingType(String drawingType, ExtensionFileFilter fileFilter) {
        DrawingTypeManager.getInstance().register(drawingType, fileFilter);
    }

    @Override
    public void unregisterDrawingType(String drawingType) {
        DrawingTypeManager.getInstance().unregister(drawingType);
    }

    @Override
    public Drawing createDrawingForDrawingType(String drawingType) {
        return DrawingTypeManager.getDrawingFromName(drawingType);
    }

    @Override
    public Locator createElbowTextLocator() {
        return new ElbowTextLocator();
    }

    @Override
    public Locator createOffsetLocator(Locator locator) {
        return new OffsetLocator(locator);
    }

    @Override
    public Locator createOffsetLocator(Locator locator, int offsetX, int offsetY) {
        return new OffsetLocator(locator, offsetX, offsetY);
    }

    @Override
    public void addExportFormat(ExportFormat<Drawing> exportFormat) {
        DrawingExportFormatHolder.getInstance().addExportFormat(exportFormat);
    }

    @Override
    public void removeExportFormat(ExportFormat<Drawing> exportFormat) {
        DrawingExportFormatHolder.getInstance().removeExportFormat(exportFormat);
    }

    @Override
    public List<ExportFormat<Drawing>> getExportFormats() {
        return DrawingExportFormatHolder.getInstance().getExportFormats();
    }

    @Override
    public void addImportFormat(ImportFormat<Drawing> importFormat) {
        DrawingImportFormatHolder.getInstance().addImportFormat(importFormat);
    }

    @Override
    public void removeImportFormat(ImportFormat<Drawing> importFormat) {
        DrawingImportFormatHolder.getInstance().removeImportFormat(importFormat);
    }

    @Override
    public List<ImportFormat<Drawing>> getImportFormats() {
        return DrawingImportFormatHolder.getInstance().getImportFormats();
    }
}
