// Copyright 2008 Google 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 com.google.gwtorm.server;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.google.gwtorm.data.Person;
import com.google.gwtorm.data.PersonAccess;
import com.google.gwtorm.data.PhoneBookDb;
import com.google.gwtorm.jdbc.Database;
import com.google.gwtorm.jdbc.JdbcExecutor;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.jdbc.SimpleDataSource;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

public class PhoneBookDbTestCase {
  private static int runCount;
  protected Database<PhoneBookDb> db;
  private List<PhoneBookDb> openSchemas;

  @Before
  public void setUp() throws Exception {
    final Properties p = new Properties();
    p.setProperty("driver", org.h2.Driver.class.getName());
    p.setProperty("url", "jdbc:h2:mem:PhoneBookDb" + (runCount++));
    db = new Database<>(new SimpleDataSource(p), PhoneBookDb.class);
    openSchemas = new ArrayList<>();
  }

  @After
  public void tearDown() throws Exception {
    if (openSchemas != null) {
      for (PhoneBookDb schema : openSchemas) {
        schema.close();
      }
      openSchemas = null;
    }
  }

  protected PhoneBookDb open() throws OrmException {
    final PhoneBookDb r = db.open();
    if (r != null) {
      openSchemas.add(r);
    }
    return r;
  }

  protected PhoneBookDb openAndCreate() throws OrmException {
    final PhoneBookDb schema = open();
    final JdbcExecutor e = new JdbcExecutor((JdbcSchema) schema);
    try {
      schema.updateSchema(e);
    } finally {
      e.close();
    }
    return schema;
  }

  protected Statement statement(final PhoneBookDb schema) throws SQLException {
    return ((JdbcSchema) schema).getConnection().createStatement();
  }

  @Test
  public void testCreateDatabaseHandle() throws Exception {
    assertNotNull(db);
  }

  @Test
  public void testOpenSchema() throws Exception {
    final PhoneBookDb schema1 = open();
    assertNotNull(schema1);

    final PhoneBookDb schema2 = open();
    assertNotNull(schema2);
    assertNotSame(schema1, schema2);
  }

  @Test
  public void testGetPeopleAccess() throws Exception {
    final PhoneBookDb schema = open();
    assertNotNull(schema.people());
    assertEquals("people", schema.people().getRelationName());
    assertEquals(1, schema.people().getRelationID());
  }

  @Test
  public void testGetAddressAccess() throws Exception {
    final PhoneBookDb schema = open();
    assertNotNull(schema.addresses());
    assertEquals("addresses", schema.addresses().getRelationName());
    assertEquals(2, schema.addresses().getRelationID());
  }

  @Test
  public void testGetAllRelations() throws Exception {
    final PhoneBookDb schema = open();
    Access<?, ?>[] all = schema.allRelations();
    assertNotNull(all);
    assertEquals(2, all.length);
    assertSame(schema.people(), all[0]);
    assertSame(schema.addresses(), all[1]);
  }

  @Test
  public void testCreateSchema() throws Exception {
    final PhoneBookDb schema = open();
    final JdbcExecutor e = new JdbcExecutor((JdbcSchema) schema);
    try {
      schema.updateSchema(e);
    } finally {
      e.close();
    }
  }

  @Test
  public void testNextAddressId() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final int a = schema.nextAddressId();
    final int b = schema.nextAddressId();
    assertTrue(a != b);
  }

  @Test
  public void testPersonPrimaryKey() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person.Key key = new Person.Key("Bob");
    final Person bob = new Person(key, 18);
    assertSame(key, schema.people().primaryKey(bob));
  }

  @Test
  public void testInsertOnePerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person bob = new Person(new Person.Key("Bob"), 18);
    schema.people().insert(Collections.singleton(bob));

    final Statement st = statement(schema);
    final ResultSet rs = st.executeQuery("SELECT name,age FROM people");
    assertTrue(rs.next());
    assertEquals(bob.name(), rs.getString(1));
    assertEquals(bob.age(), rs.getInt(2));
    assertFalse(rs.next());
    rs.close();
    st.close();
  }

  @Test
  public void testGetOnePerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final PersonAccess sp = schema.people();
    final Person p1 = new Person(new Person.Key("Bob"), 18);
    sp.insert(Collections.singleton(p1));

    final Person p2 = sp.get(sp.primaryKey(p1));
    assertNotNull(p2);
    assertNotSame(p1, p2);
    assertEquals(sp.primaryKey(p1), sp.primaryKey(p2));
  }

  @Test
  public void testGetAsyncOnePerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final PersonAccess sp = schema.people();
    final Person p1 = new Person(new Person.Key("Bob"), 18);
    sp.insert(Collections.singleton(p1));

    final Person p2 = sp.getAsync(sp.primaryKey(p1)).get();
    assertNotNull(p2);
    assertNotSame(p1, p2);
    assertEquals(sp.primaryKey(p1), sp.primaryKey(p2));
  }

  @Test
  public void testGetOnePersonIterator() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final PersonAccess sp = schema.people();
    final Person p1 = new Person(new Person.Key("Bob"), 18);
    sp.insert(Collections.singleton(p1));

    final List<Person> list =
        sp.get(Collections.singleton(sp.primaryKey(p1))).toList();
    assertNotNull(list);
    assertEquals(1, list.size());

    final Person p2 = list.get(0);
    assertNotNull(p2);
    assertNotSame(p1, p2);
    assertEquals(sp.primaryKey(p1), sp.primaryKey(p2));
  }

  @Test
  public void testInsertManyPeople() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final ArrayList<Person> all = new ArrayList<>();
    all.add(new Person(new Person.Key("Bob"), 18));
    all.add(new Person(new Person.Key("Mary"), 22));
    all.add(new Person(new Person.Key("Zak"), 33));
    schema.people().insert(all);

    final Statement st = statement(schema);
    final ResultSet rs;
    rs = st.executeQuery("SELECT name,age FROM people ORDER BY name");
    for (int rowIdx = 0; rowIdx < all.size(); rowIdx++) {
      assertTrue(rs.next());
      assertEquals(all.get(rowIdx).name(), rs.getString(1));
      assertEquals(all.get(rowIdx).age(), rs.getInt(2));
    }
    assertFalse(rs.next());
    rs.close();
    st.close();
  }

  @Test
  public void testDeleteOnePerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person bob = new Person(new Person.Key("Bob"), 18);
    schema.people().insert(Collections.singleton(bob));
    schema.people().delete(Collections.singleton(bob));

    final Statement st = statement(schema);
    final ResultSet rs = st.executeQuery("SELECT name,age FROM people");
    assertFalse(rs.next());
    rs.close();
    st.close();
  }

  @Test
  public void testUpdateOnePerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person bob = new Person(new Person.Key("Bob"), 18);
    schema.people().insert(Collections.singleton(bob));
    bob.growOlder();
    schema.people().update(Collections.singleton(bob));

    final Statement st = statement(schema);
    final ResultSet rs = st.executeQuery("SELECT name,age FROM people");
    assertTrue(rs.next());
    assertEquals(bob.name(), rs.getString(1));
    assertEquals(bob.age(), rs.getInt(2));
    assertFalse(rs.next());
    rs.close();
    st.close();
  }

  @Test
  public void testUpdateNoPerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person bob = new Person(new Person.Key("Bob"), 18);
    try {
      schema.people().update(Collections.singleton(bob));
      fail("Update of missing person succeeded");
    } catch (OrmConcurrencyException e) {
      assertEquals("Concurrent modification detected", e.getMessage());
    }
  }

  @Test
  public void testFetchOnePerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person bob = new Person(new Person.Key("Bob"), 18);
    schema.people().insert(Collections.singleton(bob));

    final List<Person> all = schema.people().all().toList();
    assertNotNull(all);
    assertEquals(1, all.size());
    assertNotSame(bob, all.get(0));
    assertEquals(bob.name(), all.get(0).name());
    assertEquals(bob.age(), all.get(0).age());
    assertEquals(bob.isRegistered(), all.get(0).isRegistered());
  }

  @Test
  public void testFetchOnePersonByName() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person bob1 = new Person(new Person.Key("Bob"), 18);
    schema.people().insert(Collections.singleton(bob1));

    final Person bob2 =
        schema.people().get(new Person.Key(bob1.name()));
    assertNotNull(bob2);
    assertNotSame(bob1, bob2);
    assertEquals(bob1.name(), bob2.name());
    assertEquals(bob1.age(), bob2.age());
    assertEquals(bob1.isRegistered(), bob2.isRegistered());
  }

  @Test
  public void testFetchByAge() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final ArrayList<Person> all = new ArrayList<>();
    all.add(new Person(new Person.Key("Bob"), 18));
    all.add(new Person(new Person.Key("Mary"), 22));
    all.add(new Person(new Person.Key("Zak"), 33));
    schema.people().insert(all);

    final List<Person> r = schema.people().olderThan(20).toList();
    assertEquals(2, r.size());
    assertEquals(all.get(1).name(), r.get(0).name());
    assertEquals(all.get(2).name(), r.get(1).name());
  }

  @Test
  public void testFetchNotPerson() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final ArrayList<Person> all = new ArrayList<>();
    all.add(new Person(new Person.Key("Bob"), 18));
    all.add(new Person(new Person.Key("Mary"), 22));
    all.add(new Person(new Person.Key("Zak"), 33));
    schema.people().insert(all);

    final List<Person> r =
        schema.people().olderThanDescByName(18).toList();
    assertEquals(2, r.size());
    assertEquals(all.get(2).name(), r.get(0).name());
    assertEquals(all.get(1).name(), r.get(1).name());
  }

  @Test
  public void testBooleanType() throws Exception {
    final PhoneBookDb schema = openAndCreate();
    final Person bob = new Person(new Person.Key("Bob"), 18);
    schema.people().insert(Collections.singleton(bob));

    final Statement st = statement(schema);
    ResultSet rs;

    rs = st.executeQuery("SELECT registered FROM people");
    assertTrue(rs.next());
    assertEquals("N", rs.getString(1));
    assertFalse(rs.next());
    rs.close();
    assertEquals(bob.isRegistered(), schema.people().all().toList().get(0)
        .isRegistered());

    bob.register();
    schema.people().update(Collections.singleton(bob));
    rs = st.executeQuery("SELECT registered FROM people");
    assertTrue(rs.next());
    assertEquals("Y", rs.getString(1));
    assertFalse(rs.next());
    rs.close();
    assertEquals(bob.isRegistered(), schema.people().all().toList().get(0)
        .isRegistered());

    bob.unregister();
    schema.people().update(Collections.singleton(bob));
    rs = st.executeQuery("SELECT registered FROM people");
    assertTrue(rs.next());
    assertEquals("N", rs.getString(1));
    assertFalse(rs.next());
    rs.close();
    assertEquals(bob.isRegistered(), schema.people().all().toList().get(0)
        .isRegistered());

    st.close();
  }
}
