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

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Represent;
import org.yaml.snakeyaml.representer.Representer;

/**
 * @see <a href="http://yaml.org/type/null.html">null</a>
 */
public class NullTagTest extends AbstractTest {

  public void testNull() {
    assertNull("Got: '" + load("---\n") + "'", load("---\n"));
    assertNull(load("---\n..."));
    assertNull(load("---\n...\n"));
    assertNull(load("\n"));
    assertNull(load(""));
    assertNull(load(" "));
    assertNull(load("~"));
    assertNull(load("---\n~"));
    assertNull(load("null"));
    assertNull(load("Null"));
    assertNull(load("NULL"));
    assertNull(getMapValue("empty:\n", "empty"));
    assertNull(getMapValue("canonical: ~", "canonical"));
    assertNull(getMapValue("english: null", "english"));
    assertNull(getMapValue("english: Null", "english"));
    assertNull(getMapValue("english: NULL", "english"));
    assertEquals("null key", getMapValue("~: null key\n", null));
  }

  @SuppressWarnings("unchecked")
  public void testSequenceNull() {
    String input =
        "---\n# This sequence has five\n# entries, two have values.\nsparse:\n  - ~\n  - 2nd entry\n  -\n  - 4th entry\n  - Null\n";
    List<String> parsed = (List<String>) getMapValue(input, "sparse");
    assertEquals(5, parsed.size());
    assertNull(parsed.get(0));
    assertEquals("2nd entry", parsed.get(1));
    assertNull("Got: '" + parsed.get(2) + "'", parsed.get(2));
    assertEquals("4th entry", parsed.get(3));
    assertNull(parsed.get(4));
  }

  public void testNullInMap() {
    String input = "key1: null\n~: value1";
    Map<String, Object> parsed = getMap(input);
    assertEquals(2, parsed.size());
    assertTrue(parsed.containsKey(null));
    Object value1 = parsed.get(null);
    assertEquals("value1", value1);
    //
    assertNull(parsed.get("key1"));
    //
    assertFalse(getMap("key2: value2").containsKey(null));
  }

  public void testNullShorthand() {
    assertNull(getMapValue("nothing: !!null null", "nothing"));
  }

  public void testNullTag() {
    assertNull(getMapValue("nothing: !<tag:yaml.org,2002:null> null", "nothing"));
  }

  public void testNullOut() {
    String output = dump(null);
    assertEquals("null\n", output);
  }

  public void testNullOutAsEmpty() {
    Yaml yaml = new Yaml(new NullRepresenter());
    String output = yaml.dump(null);
    assertEquals("", output);
  }

  /**
   * test flow style
   */
  public void testNullOutAsEmpty2() {
    Yaml yaml = new Yaml(new NullRepresenter());
    Map<String, String> map = new LinkedHashMap<String, String>();
    map.put("aaa", "foo");
    map.put("bbb", null);
    String output = yaml.dump(map);
    assertEquals("{aaa: foo, bbb: !!null ''}\n", output);
  }

  /**
   * test block style
   */
  public void testBoolOutAsEmpty3() {
    DumperOptions options = new DumperOptions();
    options.setDefaultFlowStyle(FlowStyle.BLOCK);
    Yaml yaml = new Yaml(new NullRepresenter(), options);
    Map<String, String> map = new LinkedHashMap<String, String>();
    map.put("aaa", "foo");
    map.put("bbb", null);
    String output = yaml.dump(map);
    assertEquals("aaa: foo\nbbb:\n", output);
  }

  private class NullRepresenter extends Representer {

    public NullRepresenter() {
      super(new DumperOptions());
      // null representer is exceptional, and it is stored as an instance variable.
      this.nullRepresenter = new RepresentNull();
    }

    private class RepresentNull implements Represent {

      public Node representData(Object data) {
        // possible values are here http://yaml.org/type/null.html
        return representScalar(Tag.NULL, "");
      }
    }
  }

  public void testNoAnchors() {
    List<String> list = new ArrayList<String>(3);
    list.add(null);
    list.add("value");
    list.add(null);
    Yaml yaml = new Yaml();
    String output = yaml.dump(list);
    assertEquals("Null values must not get anchors and aliases.", "[null, value, null]\n", output);
  }
}
