/*
 * DBeaver - Universal Database Manager
 * Copyright (C) 2010-2016 Serge Rieder (serge@jkiss.org)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (version 2)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.jkiss.dbeaver.ui.actions.navigator;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.IWorkbenchWindow;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.edit.DBEObjectMaker;
import org.jkiss.dbeaver.model.edit.DBEObjectManager;
import org.jkiss.dbeaver.model.navigator.DBNContainer;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseNode;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.registry.editor.EntityEditorsRegistry;
import org.jkiss.dbeaver.ui.AbstractUIJob;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.editors.IDatabaseEditor;
import org.jkiss.dbeaver.ui.editors.entity.EntityEditor;
import org.jkiss.dbeaver.ui.editors.entity.EntityEditorInput;
import org.jkiss.dbeaver.ui.navigator.database.DatabaseNavigatorView;
import org.jkiss.dbeaver.utils.GeneralUtils;

public abstract class NavigatorHandlerObjectCreateBase extends NavigatorHandlerObjectBase {

    protected boolean createNewObject(final IWorkbenchWindow workbenchWindow, DBNNode element, DBNDatabaseNode copyFrom)
    {
        try {
            DBNContainer container = null;
            if (element instanceof DBNContainer) {
                container = (DBNContainer) element;
            } else {
                DBNNode parentNode = element.getParentNode();
                if (parentNode instanceof DBNContainer) {
                    container = (DBNContainer) parentNode;
                }
            }
            if (container == null) {
                throw new DBException("Can't detect container for '" + element.getNodeName() + "'");
            }
            Class<?> childType = container.getChildrenClass();
            if (childType == null) {
                throw new DBException("Can't determine child element type for container '" + container + "'");
            }
            if (childType == IProject.class) {
                return NavigatorHandlerProjectCreate.createNewProject(workbenchWindow);
            }

            DBSObject sourceObject = copyFrom == null ? null : copyFrom.getObject();
//            if (sourceObject != null && !childType.isAssignableFrom(sourceObject.getClass())) {
//                throw new DBException("Can't create '" + childType.getName() + "' from '" + sourceObject.getClass().getName() + "'");
//            }

            final EntityEditorsRegistry editorsRegistry = EntityEditorsRegistry.getInstance();
            DBEObjectManager<?> objectManager = editorsRegistry.getObjectManager(childType);
            if (objectManager == null) {
                throw new DBException("Object manager not found for type '" + childType.getName() + "'");
            }
            DBEObjectMaker objectMaker = (DBEObjectMaker) objectManager;
            final boolean openEditor = (objectMaker.getMakerOptions() & DBEObjectMaker.FEATURE_EDITOR_ON_CREATE) != 0;
            CommandTarget commandTarget = getCommandTarget(
                workbenchWindow,
                container,
                childType,
                openEditor);

            final Object parentObject = container.getValueObject();
            createDatabaseObject(commandTarget, objectMaker, parentObject, sourceObject);
        }
        catch (Throwable e) {
            UIUtils.showErrorDialog(workbenchWindow.getShell(), "Create object", null, e);
            return false;
        }

        return true;
    }

    private <OBJECT_TYPE extends DBSObject, CONTAINER_TYPE> void createDatabaseObject(
        CommandTarget commandTarget,
        DBEObjectMaker<OBJECT_TYPE, CONTAINER_TYPE> objectMaker,
        CONTAINER_TYPE parentObject,
        DBSObject sourceObject) throws DBException
    {
        final CreateJob<OBJECT_TYPE, CONTAINER_TYPE> job = new CreateJob<>(commandTarget, objectMaker, parentObject, sourceObject);
        job.schedule();
    }

    static class CreateJob<OBJECT_TYPE extends DBSObject, CONTAINER_TYPE> extends AbstractUIJob {
        private final CommandTarget commandTarget;
        private final DBEObjectMaker<OBJECT_TYPE, CONTAINER_TYPE> objectMaker;
        private final CONTAINER_TYPE parentObject;
        private final DBSObject sourceObject;
        private OBJECT_TYPE newObject;

        public CreateJob(CommandTarget commandTarget, DBEObjectMaker<OBJECT_TYPE, CONTAINER_TYPE> objectMaker, CONTAINER_TYPE parentObject, DBSObject sourceObject) {
            super("Create new database object with " + objectMaker);
            this.commandTarget = commandTarget;
            this.objectMaker = objectMaker;
            this.parentObject = parentObject;
            this.sourceObject = sourceObject;
        }

        @Override
        protected IStatus runInUIThread(DBRProgressMonitor monitor) {
            try {
                newObject = objectMaker.createNewObject(monitor, commandTarget.getContext(), parentObject, sourceObject);
                if (newObject == null) {
                    return Status.CANCEL_STATUS;
                }
                if ((objectMaker.getMakerOptions() & DBEObjectMaker.FEATURE_SAVE_IMMEDIATELY) != 0) {
                    // Save object manager's content
                    commandTarget.getContext().saveChanges(monitor);
                }

                IWorkbenchWindow workbenchWindow = DBeaverUI.getActiveWorkbenchWindow();
                try {
                    final boolean openEditor = (objectMaker.getMakerOptions() & DBEObjectMaker.FEATURE_EDITOR_ON_CREATE) != 0;

                    final DBNDatabaseNode newChild = DBeaverCore.getInstance().getNavigatorModel().findNode(newObject);
                    if (newChild != null) {
                        DatabaseNavigatorView view = UIUtils.findView(workbenchWindow, DatabaseNavigatorView.class);
                        if (view != null) {
                            view.showNode(newChild);
                        }
                        IDatabaseEditor editor = commandTarget.getEditor();
                        if (editor != null) {
                            // Just activate existing editor
                            workbenchWindow.getActivePage().activate(editor);
                        } else if (openEditor) {
                            // Open new one with existing context
                            EntityEditorInput editorInput = new EntityEditorInput(
                                newChild,
                                commandTarget.getContext());
                            workbenchWindow.getActivePage().openEditor(
                                editorInput,
                                EntityEditor.class.getName());
                        }
                    } else {
                        throw new DBException("Can't find node corresponding to new object");
                    }
                } catch (Throwable e) {
                    UIUtils.showErrorDialog(workbenchWindow.getShell(), "Create object", null, e);
                }

                return Status.OK_STATUS;
            } catch (Exception e) {
                return GeneralUtils.makeExceptionStatus(e);
            }
        }

    }

}
@@ -3188,24 +3188,132 @@
 tObject();%0D%0A
+            // Do not check for type - manager must do it. Potentially we can copy anything into anything.%0D%0A
 //          

Copy table from abstract entity (MySQL)