/**
 * Copyright (c) 2008, SnakeYAML
 *
 * 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.yaml.snakeyaml.constructor;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import junit.framework.TestCase;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Util;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.YamlCreator;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;

public class TypeSafeCollectionsTest extends TestCase {

  public void testTypeSafeList() {
    Constructor constructor = new Constructor(Car.class, new LoaderOptions());
    TypeDescription carDescription = new TypeDescription(Car.class);
    carDescription.putListPropertyType("wheels", Wheel.class);
    constructor.addTypeDescription(carDescription);
    Yaml yaml = new Yaml(constructor);
    Car car = yaml.load(Util.getLocalResource("constructor/car-no-root-class.yaml"));
    assertEquals("12-XP-F4", car.getPlate());
    List<Wheel> wheels = car.getWheels();
    assertNotNull(wheels);
    assertEquals(5, wheels.size());
    for (Wheel wheel : wheels) {
      assertTrue(wheel.getId() > 0);
    }
  }

  public void testTypeSafeMap() {
    Constructor constructor = new Constructor(MyCar.class, new LoaderOptions());
    TypeDescription carDescription = new TypeDescription(MyCar.class);
    carDescription.putMapPropertyType("wheels", MyWheel.class, Object.class);
    constructor.addTypeDescription(carDescription);
    Yaml yaml = new Yaml(constructor);
    MyCar car = yaml.load(Util.getLocalResource("constructor/car-no-root-class-map.yaml"));
    assertEquals("00-FF-Q2", car.getPlate());
    Map<MyWheel, Date> wheels = car.getWheels();
    assertNotNull(wheels);
    assertEquals(5, wheels.size());
    for (MyWheel wheel : wheels.keySet()) {
      assertTrue(wheel.getId() > 0);
      Date date = wheels.get(wheel);
      long time = date.getTime();
      assertEquals("It must be midnight.", 0, time % 10000);
    }
  }

  public void testTypeSafeList2() {
    Constructor constructor = new Constructor(Car.class, new LoaderOptions());
    TypeDescription carDescription = new TypeDescription(Car.class);
    carDescription.addPropertyParameters("wheels", Wheel.class);
    constructor.addTypeDescription(carDescription);
    Yaml yaml = new Yaml(constructor);
    Car car = yaml.load(Util.getLocalResource("constructor/car-no-root-class.yaml"));
    assertEquals("12-XP-F4", car.getPlate());
    List<Wheel> wheels = car.getWheels();
    assertNotNull(wheels);
    assertEquals(5, wheels.size());
    for (Wheel wheel : wheels) {
      assertTrue(wheel.getId() > 0);
    }
  }

  public void testTypeSafeMap2() {
    Constructor constructor = new Constructor(MyCar.class, new LoaderOptions());
    TypeDescription carDescription = new TypeDescription(MyCar.class);
    carDescription.addPropertyParameters("wheels", MyWheel.class, Object.class);
    constructor.addTypeDescription(carDescription);
    Yaml yaml = new Yaml(constructor);
    MyCar car = yaml.load(Util.getLocalResource("constructor/car-no-root-class-map.yaml"));
    assertEquals("00-FF-Q2", car.getPlate());
    Map<MyWheel, Date> wheels = car.getWheels();
    assertNotNull(wheels);
    assertEquals(5, wheels.size());
    for (MyWheel wheel : wheels.keySet()) {
      assertTrue(wheel.getId() > 0);
      Date date = wheels.get(wheel);
      long time = date.getTime();
      assertEquals("It must be midnight.", 0, time % 10000);
    }
  }

  public void testWithGlobalTag() {
    Map<MyWheel, Date> wheels = new TreeMap<MyWheel, Date>();
    long time = 1248212168084L;
    for (int i = 1; i < 6; i++) {
      MyWheel mw = new MyWheel();
      mw.setId(i);
      mw.setBrand(mw.getBrand() + i);
      wheels.put(mw, new Date(time + i));
    }
    MyCar c = new MyCar();
    c.setPlate("00-FF-Q2");
    c.setWheels(wheels);
    Representer representer = new Representer(new DumperOptions());
    representer.addClassTag(MyWheel.class, Tag.MAP);
    Yaml yaml = new Yaml(representer);
    String output = yaml.dump(c);
    assertEquals(Util.getLocalResource("javabeans/mycar-with-global-tag1.yaml"), output);
    // load
    Yaml beanLoader = YamlCreator.allowClassPrefix("org.yaml.snakeyaml");
    MyCar car = beanLoader.loadAs(output, MyCar.class);
    assertNotNull(car);
    assertEquals("00-FF-Q2", car.getPlate());
    assertEquals(5, car.getWheels().size());
    for (Date d : car.getWheels().values()) {
      // give a day for any timezone
      assertTrue(d.before(new Date(time + 1000 * 60 * 60 * 24)));
      assertTrue(d.after(new Date(time)));
    }
    Object wheel = car.getWheels().keySet().iterator().next();
    assertTrue(wheel instanceof MyWheel);
    MyWheel w = (MyWheel) wheel;
    assertEquals(1, w.getId());
    assertEquals("Pirelli1", w.getBrand());
  }
}
