/*
 * Copyright (c) 2008-2016 MongoDB, Inc.
 *
 * 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.mongodb.morphia.entities;

import org.bson.types.ObjectId;
import org.junit.Assert;
import org.junit.Test;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.TestBase;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Id;
import org.mongodb.morphia.query.Query;
import org.mongodb.morphia.query.UpdateOperations;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class TestEmbeddedValidation extends TestBase {

    @Test
    @SuppressWarnings("unchecked")
    public void testCreateEntityWithBasicDBList() {
        getMorphia().map(TestEntity.class);
        TestEntity entity = new TestEntity();

        Map<String, Object> map = mapOf("type", "text");
        map.put("data", mapOf("text", "sometext"));

        Map<String, Object> map1 = mapOf("data", mapOf("id", "123"));
        map1.put("type", "image");
        List<Map<String, Object>> data = asList(map, map1);

        entity.setData(data);
        getDatastore().save(entity);

        TestEntity testEntity = getDatastore().get(TestEntity.class, entity.getId());
        assertEquals(entity, testEntity);

        Query<TestEntity> query = getDatastore().createQuery(TestEntity.class);
        query.disableValidation();
        query.criteria("data.data.id").equal("123");

        assertNotNull(query.get());
    }

    @Test
    public void testDottedNames() {
        ParentType parentType = new ParentType();
        EmbeddedSubtype embedded = new EmbeddedSubtype();
        embedded.setText("text");
        embedded.setNumber(42L);
        embedded.setFlag(true);
        parentType.setEmbedded(embedded);

        Datastore ds = getDatastore();
        ds.save(parentType);

        Query<ParentType> query = ds.find(ParentType.class)
                                    .disableValidation()
                                    .field("embedded.flag").equal(true);

        Assert.assertEquals(parentType, query.get());
    }

    @Test
    public void testEmbeddedListQueries() {
        EntityWithListsAndArrays entity = new EntityWithListsAndArrays();
        EmbeddedType fortyTwo = new EmbeddedType(42L, "forty-two");
        entity.setListEmbeddedType(asList(fortyTwo, new EmbeddedType(1L, "one")));
        getDatastore().save(entity);

        Query<EntityWithListsAndArrays> query = getDatastore().find(EntityWithListsAndArrays.class)
                                                              .field("listEmbeddedType.number").equal(42L);
        List<EntityWithListsAndArrays> list = query.asList();

        Assert.assertEquals(1, list.size());
        Assert.assertEquals(fortyTwo, list.get(0).getListEmbeddedType().get(0));

        UpdateOperations<EntityWithListsAndArrays> operations = getDatastore()
            .createUpdateOperations(EntityWithListsAndArrays.class)
            .set("listEmbeddedType.$.number", 0);
        getDatastore().updateMany(query, operations);

        Assert.assertEquals(0, query.count());

        fortyTwo.setNumber(0L);
        query = getDatastore().find(EntityWithListsAndArrays.class)
                              .field("listEmbeddedType.number").equal(0);
        list = query.asList();

        Assert.assertEquals(1, list.size());
        Assert.assertEquals(fortyTwo, list.get(0).getListEmbeddedType().get(0));

    }

    private Map<String, Object> mapOf(final String key, final Object value) {
        HashMap<String, Object> map = new HashMap<>();
        map.put(key, value);
        return map;
    }

    @Entity
    public static class TestEntity {

        @Id
        private ObjectId id;
        private List<Map<String, Object>> data;

        public List<Map<String, Object>> getData() {
            return data;
        }

        public void setData(final List<Map<String, Object>> data) {
            this.data = new ArrayList<>();
            this.data.addAll(data);
        }

        public ObjectId getId() {
            return id;
        }

        @Override
        public int hashCode() {
            int result = getId() != null ? getId().hashCode() : 0;
            result = 31 * result + (getData() != null ? getData().hashCode() : 0);
            return result;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (!(o instanceof TestEntity)) {
                return false;
            }

            final TestEntity that = (TestEntity) o;

            if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) {
                return false;
            }
            return getData() != null ? getData().equals(that.getData()) : that.getData() == null;

        }
    }
}

@@ -1006,34 +1006,8 @@
 st;%0A
-import java.util.HashMap;%0A
 impo
@@ -1239,881 +1239,8 @@
  %7B%0A%0A
-    @Test%0A    @SuppressWarnings(%22unchecked%22)%0A    public void testCreateEntityWithBasicDBList() %7B%0A        getMorphia().map(TestEntity.class);%0A        TestEntity entity = new TestEntity();%0A%0A        Map%3CString, Object%3E map = mapOf(%22type%22, %22text%22);%0A        map.put(%22data%22, mapOf(%22text%22, %22sometext%22));%0A%0A        Map%3CString, Object%3E map1 = mapOf(%22data%22, mapOf(%22id%22, %22123%22));%0A        map1.put(%22type%22, %22image%22);%0A        List%3CMap%3CString, Object%3E%3E data = asList(map, map1);%0A%0A        entity.setData(data);%0A        getDatastore().save(entity);%0A%0A        TestEntity testEntity = getDatastore().get(TestEntity.class, entity.getId());%0A        assertEquals(entity, testEntity);%0A%0A        Query%3CTestEntity%3E query = getDatastore().createQuery(TestEntity.class);%0A        query.disableValidation();%0A        query.criteria(%22data.data.id%22).equal(%22123%22);%0A%0A        assertNotNull(query.get());%0A    %7D%0A%0A
     
@@ -3211,197 +3211,8 @@
  %7D%0A%0A
-    private Map%3CString, Object%3E mapOf(final String key, final Object value) %7B%0A        HashMap%3CString, Object%3E map = new HashMap%3C%3E();%0A        map.put(key, value);%0A        return map;%0A    %7D%0A%0A
     

remove pointless test