// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.datastore.driver;

import java.util.Map;

import javax.inject.Inject;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcContext;
import org.apache.cloudstack.storage.command.CommandResult;
import org.apache.cloudstack.storage.command.CreateObjectCommand;
import org.apache.cloudstack.storage.datastore.DataObjectManager;

import com.cloud.agent.api.Answer;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.DataTO;
import com.cloud.host.Host;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;

public class SamplePrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver {
    protected Logger logger = LogManager.getLogger(getClass());
    @Inject
    EndPointSelector selector;
    @Inject
    StoragePoolHostDao storeHostDao;
    @Inject
    DataObjectManager dataObjMgr;

    public SamplePrimaryDataStoreDriverImpl() {

    }

    @Override
    public Map<String, String> getCapabilities() {
        return null;
    }

    @Override
    public DataTO getTO(DataObject data) {
        return null;
    }

    @Override
    public DataStoreTO getStoreTO(DataStore store) {
        return null;
    }

    @Override
    public ChapInfo getChapInfo(DataObject dataObject) {
        return null;
    }

    @Override
    public boolean grantAccess(DataObject dataObject, Host host, DataStore dataStore) { return false; }

    @Override
    public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) {}

    @Override
    public long getUsedBytes(StoragePool storagePool) {
        return 0;
    }

    @Override
    public long getUsedIops(StoragePool storagePool) {
        return 0;
    }

    @Override
    public long getDataObjectSizeIncludingHypervisorSnapshotReserve(DataObject dataObject, StoragePool pool) {
        return dataObject.getSize();
    }

    @Override
    public long getBytesRequiredForTemplate(TemplateInfo templateInfo, StoragePool storagePool) {
        return 0;
    }

    private class CreateVolumeContext<T> extends AsyncRpcContext<T> {
        public CreateVolumeContext(AsyncCompletionCallback<T> callback, DataObject volume) {
            super(callback);
        }
    }

    public Void createAsyncCallback(AsyncCallbackDispatcher<SamplePrimaryDataStoreDriverImpl, Answer> callback, CreateVolumeContext<CreateCmdResult> context) {
        /*
         * CreateCmdResult result = null; CreateObjectAnswer volAnswer =
         * (CreateObjectAnswer) callback.getResult(); if (volAnswer.getResult())
         * { result = new CreateCmdResult(volAnswer.getPath(), volAnswer); }
         * else { result = new CreateCmdResult("", null);
         * result.setResult(volAnswer.getDetails()); }
         *
         * context.getParentCallback().complete(result);
         */
        return null;
    }

    @Override
    public void deleteAsync(DataStore dataStore, DataObject vo, AsyncCompletionCallback<CommandResult> callback) {
        /*
         * DeleteCommand cmd = new DeleteCommand(vo.getUri());
         *
         * EndPoint ep = selector.select(vo); AsyncRpcContext<CommandResult>
         * context = new AsyncRpcContext<CommandResult>(callback);
         * AsyncCallbackDispatcher<SamplePrimaryDataStoreDriverImpl, Answer>
         * caller = AsyncCallbackDispatcher.create(this);
         * caller.setCallback(caller.getTarget().deleteCallback(null, null))
         * .setContext(context); ep.sendMessageAsync(cmd, caller);
         */
    }

    public Void deleteCallback(AsyncCallbackDispatcher<SamplePrimaryDataStoreDriverImpl, Answer> callback, AsyncRpcContext<CommandResult> context) {
        CommandResult result = new CommandResult();
        Answer answer = callback.getResult();
        if (!answer.getResult()) {
            result.setResult(answer.getDetails());
        }
        context.getParentCallback().complete(result);
        return null;
    }

    /*
     * private class CreateVolumeFromBaseImageContext<T> extends
     * AsyncRpcContext<T> { private final VolumeObject volume;
     *
     * public CreateVolumeFromBaseImageContext(AsyncCompletionCallback<T>
     * callback, VolumeObject volume) { super(callback); this.volume = volume; }
     *
     * public VolumeObject getVolume() { return this.volume; }
     *
     * }
     *
     * @Override public void createVolumeFromBaseImageAsync(VolumeObject volume,
     * TemplateInfo template, AsyncCompletionCallback<CommandResult> callback) {
     * VolumeTO vol = this.dataStore.getVolumeTO(volume); List<EndPoint>
     * endPoints = this.dataStore.getEndPoints(); EndPoint ep =
     * endPoints.get(0); String templateUri =
     * template.getDataStore().grantAccess(template, ep);
     * CreateVolumeFromBaseImageCommand cmd = new
     * CreateVolumeFromBaseImageCommand(vol, templateUri);
     *
     * CreateVolumeFromBaseImageContext<CommandResult> context = new
     * CreateVolumeFromBaseImageContext<CommandResult>(callback, volume);
     * AsyncCallbackDispatcher<DefaultPrimaryDataStoreDriverImpl, Answer> caller
     * = AsyncCallbackDispatcher.create(this); caller.setContext(context)
     * .setCallback
     * (caller.getTarget().createVolumeFromBaseImageAsyncCallback(null, null));
     *
     * ep.sendMessageAsync(cmd, caller); }
     */
    /*
     * public Object
     * createVolumeFromBaseImageAsyncCallback(AsyncCallbackDispatcher
     * <DefaultPrimaryDataStoreDriverImpl, Answer> callback,
     * CreateVolumeFromBaseImageContext<CommandResult> context) {
     * CreateVolumeAnswer answer = (CreateVolumeAnswer)callback.getResult();
     * CommandResult result = new CommandResult(); if (answer == null ||
     * answer.getDetails() != null) { result.setSuccess(false); if (answer !=
     * null) { result.setResult(answer.getDetails()); } } else {
     * result.setSuccess(true); VolumeObject volume = context.getVolume();
     * volume.setPath(answer.getVolumeUuid()); }
     * AsyncCompletionCallback<CommandResult> parentCall =
     * context.getParentCallback(); parentCall.complete(result); return null; }
     */

    @Override
    public void createAsync(DataStore dataStore, DataObject vol, AsyncCompletionCallback<CreateCmdResult> callback) {
        EndPoint ep = selector.select(vol);
        if (ep == null) {
            String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
            logger.error(errMsg);
            throw new CloudRuntimeException(errMsg);
        }
        CreateObjectCommand createCmd = new CreateObjectCommand(null);

        CreateVolumeContext<CreateCmdResult> context = new CreateVolumeContext<CreateCmdResult>(callback, vol);
        AsyncCallbackDispatcher<SamplePrimaryDataStoreDriverImpl, Answer> caller = AsyncCallbackDispatcher.create(this);
        caller.setContext(context).setCallback(caller.getTarget().createAsyncCallback(null, null));

        ep.sendMessageAsync(createCmd, caller);
    }

    @Override
    public void revertSnapshot(SnapshotInfo snapshot, SnapshotInfo snapshotOnPrimaryStore, AsyncCompletionCallback<CommandResult> callback) {
    }

    @Override
    public boolean canCopy(DataObject srcData, DataObject destData) {
        return false;
    }

    @Override
    public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
    }

    @Override
    public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
    }

    @Override
    public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
    }

    @Override
    public void handleQualityOfServiceForVolumeMigration(VolumeInfo volumeInfo, QualityOfServiceState qualityOfServiceState) {
    }

    @Override
    public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback<CreateCmdResult> callback) {
    }

    @Override
    public boolean canProvideStorageStats() {
        return false;
    }

    @Override
    public boolean canProvideVolumeStats() {
        return false;
    }

    @Override
    public Pair<Long, Long> getVolumeStats(StoragePool storagePool, String volumeId) {
        return null;
    }

    @Override
    public Pair<Long, Long> getStorageStats(StoragePool storagePool) {
        return null;
    }

    @Override
    public boolean canHostAccessStoragePool(Host host, StoragePool pool) {
        return true;
    }

    @Override
    public boolean isVmInfoNeeded() {
        return false;
    }

    @Override
    public void provideVmInfo(long vmId, long volumeId) {
    }

    @Override
    public boolean isVmTagsNeeded(String tagKey) {
        return false;
    }

    @Override
    public void provideVmTags(long vmId, long volumeId, String tagValue) {
    }

    @Override
    public boolean isStorageSupportHA(StoragePoolType type) {
        return false;
    }

    @Override
    public void detachVolumeFromAllStorageNodes(Volume volume) {
    }
}
