// Path: src/main/java/org/springframework/data/cloudant/config/ICloudantConnector.java
// public interface ICloudantConnector {
//     CloudantClient getClient();
// 
//     String getDbName();
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/mapping/event/AfterSaveEvent.java
// public class AfterSaveEvent<E extends BaseDocument> extends CloudantMappingEvent<E> {
// 
//     public AfterSaveEvent(E source) {
//         super(source, null);
//     }
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/mapping/event/BeforeSaveEvent.java
// public class BeforeSaveEvent<E extends BaseDocument> extends CloudantMappingEvent<E> {
// 
//     public BeforeSaveEvent(E source) {
//         super(source, null);
//     }
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/mapping/event/CloudantMappingEvent.java
// public class CloudantMappingEvent<T> extends ApplicationEvent {
// 
//     private final Document document;
// 
//     public CloudantMappingEvent(T source, Document document) {
//         super(source);
//         this.document = document;
//     }
// 
//     public Document getDocument() {
//         return document;
//     }
// 
//     @SuppressWarnings("unchecked")
//     @Override
//     public T getSource() {
//         return (T) super.getSource();
//     }
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/model/BaseDocument.java
// @JsonInclude(JsonInclude.Include.ALWAYS)
// public class BaseDocument {
// 
//     @SerializedName("_id")
//     @Id
//     private String id;
// 
//     @SerializedName("_rev")
//     private String revision;
// 
//     //json ignore
//     @JsonIgnore
//     private Map<String, Object> unmappedFields;
// 
//     @JsonProperty("_id")
//     public String getId() {
//         return id;
//     }
// 
//     @JsonProperty("_id")
//     public void setId(String id) {
//         this.id = id;
//     }
// 
//     @JsonProperty("_rev")
//     public String getRevision() {
//         return revision;
//     }
// 
//     @JsonProperty("_rev")
//     public void setRevision(String revision) {
//         this.revision = revision;
//     }
// 
//     public void setUnmappedFields(Map<String, Object> unmappedFields) {
//         this.unmappedFields = unmappedFields;
//     }
// 
//     public Map<String, Object> getUnmappedFields() {
//         return unmappedFields;
//     }
// 
//     public void addUnmappedField(String key, Object value) {
//         if (unmappedFields == null) {
//             unmappedFields = new HashMap<String, Object>();
//         }
//         unmappedFields.put(key,value);
//     }
// }


import com.cloudant.client.api.CloudantClient;
import com.cloudant.client.api.Database;
import com.cloudant.client.api.model.*;
import com.google.gson.GsonBuilder;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.cloudant.config.ICloudantConnector;
import org.springframework.data.cloudant.core.mapping.event.AfterSaveEvent;
import org.springframework.data.cloudant.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.cloudant.core.mapping.event.CloudantMappingEvent;
import org.springframework.data.cloudant.core.model.BaseDocument;
import org.springframework.data.domain.Pageable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/*
 *
 *  * Copyright 2010-2012 the original author or authors.
 *  *
 *  * Licensed 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.springframework.data.cloudant.core;



/**
 * Created by justinsaul on 6/9/15.
 */
public class CloudantTemplate<T extends BaseDocument> implements CloudantOperations<T>, ApplicationEventPublisherAware {

    private CloudantClient client;
    private final CloudantExceptionTranslator exceptionTranslator = new CloudantExceptionTranslator();
    private ApplicationEventPublisher eventPublisher;
    private Database database;
    private final Logger logger = LoggerFactory.getLogger(CloudantTemplate.class);

    // the constructor using false as default in create parameter
    public CloudantTemplate(final ICloudantConnector dbConnector){
        this.client = dbConnector.getClient();
        this.database = this.client.database(dbConnector.getDbName(), false);
    }

    // the constructor using false as default in create parameter
    public CloudantTemplate(final CloudantClient client, final String databaseName) {
        this.client = client;
        this.database = this.client.database(databaseName, false);
    }

    public CloudantTemplate(final ICloudantConnector dbConnector, Boolean create){
        this.client = dbConnector.getClient();
        this.database = this.client.database(dbConnector.getDbName(), create);
    }
    public CloudantTemplate(final CloudantClient client, final String databaseName, Boolean create) {
        this.client = client;
        this.database = this.client.database(databaseName, create);
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.eventPublisher = applicationEventPublisher;
    }

    @Override
    public T save(T obj) {

// Path: src/main/java/org/springframework/data/cloudant/config/ICloudantConnector.java
// public interface ICloudantConnector {
//     CloudantClient getClient();
// 
//     String getDbName();
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/mapping/event/AfterSaveEvent.java
// public class AfterSaveEvent<E extends BaseDocument> extends CloudantMappingEvent<E> {
// 
//     public AfterSaveEvent(E source) {
//         super(source, null);
//     }
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/mapping/event/BeforeSaveEvent.java
// public class BeforeSaveEvent<E extends BaseDocument> extends CloudantMappingEvent<E> {
// 
//     public BeforeSaveEvent(E source) {
//         super(source, null);
//     }
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/mapping/event/CloudantMappingEvent.java
// public class CloudantMappingEvent<T> extends ApplicationEvent {
// 
//     private final Document document;
// 
//     public CloudantMappingEvent(T source, Document document) {
//         super(source);
//         this.document = document;
//     }
// 
//     public Document getDocument() {
//         return document;
//     }
// 
//     @SuppressWarnings("unchecked")
//     @Override
//     public T getSource() {
//         return (T) super.getSource();
//     }
// }
// 
// Path: src/main/java/org/springframework/data/cloudant/core/model/BaseDocument.java
// @JsonInclude(JsonInclude.Include.ALWAYS)
// public class BaseDocument {
// 
//     @SerializedName("_id")
//     @Id
//     private String id;
// 
//     @SerializedName("_rev")
//     private String revision;
// 
//     //json ignore
//     @JsonIgnore
//     private Map<String, Object> unmappedFields;
// 
//     @JsonProperty("_id")
//     public String getId() {
//         return id;
//     }
// 
//     @JsonProperty("_id")
//     public void setId(String id) {
//         this.id = id;
//     }
// 
//     @JsonProperty("_rev")
//     public String getRevision() {
//         return revision;
//     }
// 
//     @JsonProperty("_rev")
//     public void setRevision(String revision) {
//         this.revision = revision;
//     }
// 
//     public void setUnmappedFields(Map<String, Object> unmappedFields) {
//         this.unmappedFields = unmappedFields;
//     }
// 
//     public Map<String, Object> getUnmappedFields() {
//         return unmappedFields;
//     }
// 
//     public void addUnmappedField(String key, Object value) {
//         if (unmappedFields == null) {
//             unmappedFields = new HashMap<String, Object>();
//         }
//         unmappedFields.put(key,value);
//     }
// }


// Path: src/main/java/org/springframework/data/cloudant/core/CloudantTemplate.java
import com.cloudant.client.api.CloudantClient;
import com.cloudant.client.api.Database;
import com.cloudant.client.api.model.*;
import com.google.gson.GsonBuilder;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.cloudant.config.ICloudantConnector;
import org.springframework.data.cloudant.core.mapping.event.AfterSaveEvent;
import org.springframework.data.cloudant.core.mapping.event.BeforeSaveEvent;
import org.springframework.data.cloudant.core.mapping.event.CloudantMappingEvent;
import org.springframework.data.cloudant.core.model.BaseDocument;
import org.springframework.data.domain.Pageable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/*
 *
 *  * Copyright 2010-2012 the original author or authors.
 *  *
 *  * Licensed 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.springframework.data.cloudant.core;



/**
 * Created by justinsaul on 6/9/15.
 */
public class CloudantTemplate<T extends BaseDocument> implements CloudantOperations<T>, ApplicationEventPublisherAware {

    private CloudantClient client;
    private final CloudantExceptionTranslator exceptionTranslator = new CloudantExceptionTranslator();
    private ApplicationEventPublisher eventPublisher;
    private Database database;
    private final Logger logger = LoggerFactory.getLogger(CloudantTemplate.class);

    // the constructor using false as default in create parameter
    public CloudantTemplate(final ICloudantConnector dbConnector){
        this.client = dbConnector.getClient();
        this.database = this.client.database(dbConnector.getDbName(), false);
    }

    // the constructor using false as default in create parameter
    public CloudantTemplate(final CloudantClient client, final String databaseName) {
        this.client = client;
        this.database = this.client.database(databaseName, false);
    }

    public CloudantTemplate(final ICloudantConnector dbConnector, Boolean create){
        this.client = dbConnector.getClient();
        this.database = this.client.database(dbConnector.getDbName(), create);
    }
    public CloudantTemplate(final CloudantClient client, final String databaseName, Boolean create) {
        this.client = client;
        this.database = this.client.database(databaseName, create);
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.eventPublisher = applicationEventPublisher;
    }

    @Override
    public T save(T obj) {

        maybeEmitEvent(new BeforeSaveEvent<T>(obj));