/**
 * 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 examples.jodatime;

import java.util.Date;
import junit.framework.TestCase;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.AbstractConstruct;
import org.yaml.snakeyaml.constructor.Construct;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeId;
import org.yaml.snakeyaml.nodes.Tag;

public class JodaTimeExampleTest extends TestCase {

  private static final long timestamp = 1000000000000L;

  public void testDump() {
    DateTime time = new DateTime(timestamp, DateTimeZone.UTC);
    Yaml yaml = new Yaml(new JodaTimeRepresenter());
    String joda = yaml.dump(time);
    String date = new Yaml().dump(new Date(timestamp));
    assertEquals(date, joda);
    assertEquals("2001-09-09T01:46:40Z\n", joda);
  }

  public void testLoad() {
    Yaml yaml = new Yaml(new JodaTimeImplicitContructor());
    DateTime time = yaml.load("2001-09-09T01:46:40Z");
    assertEquals(new DateTime(timestamp, DateTimeZone.UTC), time);
  }

  /**
   * test issue 109
   */
  public void test109() {
    Date someDate = new DateMidnight(9, 2, 21, DateTimeZone.forID("Europe/Amsterdam")).toDate();
    Yaml yaml = new Yaml();
    String timestamp = yaml.dump(someDate);
    assertEquals("0009-02-22T23:40:28Z\n", timestamp);
    // System.out.println(timestamp);
    Object o = yaml.load(timestamp);
    assertEquals(someDate, o);
  }

  class JodaPropertyConstructor extends Constructor {

    public JodaPropertyConstructor() {
      super(new LoaderOptions());
      yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct());
    }

    class TimeStampConstruct extends Constructor.ConstructScalar {

      @Override
      public Object construct(Node nnode) {
        if (nnode.getTag().equals("tag:yaml.org,2002:timestamp")) {
          Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
          Date date = (Date) dateConstructor.construct(nnode);
          return new DateTime(date, DateTimeZone.UTC);
        } else {
          return super.construct(nnode);
        }
      }
    }
  }

  /**
   * This class should be used if JodaTime may appear with a tag or as a JavaBean property
   */
  public class JodaTimeConstructor extends Constructor {

    private final Construct javaDateConstruct;
    private final Construct jodaDateConstruct;

    public JodaTimeConstructor() {
      super(new LoaderOptions());
      javaDateConstruct = new ConstructYamlTimestamp();
      jodaDateConstruct = new ConstructJodaTimestamp();
      // Whenever we see an explicit timestamp tag, make a Joda Date
      // instead
      yamlConstructors.put(Tag.TIMESTAMP, jodaDateConstruct);
      // See
      // We need this to work around implicit construction.
      yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct());
    }

    public class ConstructJodaTimestamp extends AbstractConstruct {

      public Object construct(Node node) {
        Date date = (Date) javaDateConstruct.construct(node);
        return new DateTime(date, DateTimeZone.UTC);
      }
    }

    class TimeStampConstruct extends Constructor.ConstructScalar {

      @Override
      public Object construct(Node nnode) {
        if (nnode.getTag().equals(Tag.TIMESTAMP)) {
          return jodaDateConstruct.construct(nnode);
        } else {
          return super.construct(nnode);
        }
      }
    }
  }
}
