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

import static org.junit.Assert.assertNotEquals;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import junit.framework.TestCase;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.YamlCreator;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;

/**
 * issue 82: property order influence when aliased in generic collection
 */
public class PropOrderInfluenceWhenAliasedInGenericCollectionTest extends TestCase {

  public interface Account {

  }

  public static class GeneralAccount implements Account {

    public String name = "General";
  }

  public static class SuperSaverAccount extends GeneralAccount {

    public SuperSaverAccount() {
      name = "SuperSaver";
    }
  }

  public static class CustomerAB {

    public Collection<Account> aAll;
    public Collection<GeneralAccount> bGeneral;

    @Override
    public String toString() {
      return "CustomerAB";
    }
  }

  public static class CustomerBA {

    public Collection<GeneralAccount> aGeneral;
    public Collection<Account> bAll;
  }

  public static class CustomerAB_MapValue {

    public Collection<Account> aAll;
    public Map<String, GeneralAccount> bGeneralMap;

    @Override
    public String toString() {
      return "CustomerAB_MapValue";
    }
  }

  public static class CustomerAB_MapKey {

    public Collection<Account> aAll;
    public Map<GeneralAccount, String> bGeneralMap;

    @Override
    public String toString() {
      return "CustomerAB_MapKey";
    }
  }

  public static class CustomerAB_Property {

    public Account acc;
    public Collection<GeneralAccount> bGeneral;

    @Override
    public String toString() {
      return "CustomerAB_Property";
    }
  }

  public void testAB() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB customerAB = new CustomerAB();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
    general.add(generalAccount);
    general.add(supersaver);

    customerAB.aAll = all;
    customerAB.bGeneral = general;

    Yaml yaml = YamlCreator.allowClassPrefix("org.yaml.snakeyaml");
    String dump = yaml.dump(customerAB);
    // System.out.println(dump);
    CustomerAB parsed = yaml.load(dump);
    assertNotNull(parsed);
  }

  public void testAB_Set() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB customerAB = new CustomerAB();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    Set<GeneralAccount> general = new HashSet<GeneralAccount>();
    general.add(generalAccount);
    general.add(supersaver);

    customerAB.aAll = all;
    customerAB.bGeneral = general;

    Yaml yaml = YamlCreator.allowClassPrefix("org.yaml.snakeyaml");
    String dump = yaml.dump(customerAB);
    // System.out.println(dump);
    CustomerAB parsed = yaml.load(dump);
    assertNotNull(parsed);
  }

  public void testABWithCustomTag() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB customerAB = new CustomerAB();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
    general.add(generalAccount);
    general.add(supersaver);

    customerAB.aAll = all;
    customerAB.bGeneral = general;

    Constructor constructor =
        new Constructor(YamlCreator.trustPrefixLoaderOptions("org.yaml.snakeyaml"));
    Representer representer = new Representer(new DumperOptions());
    Tag generalAccountTag = new Tag("!GA");
    constructor.addTypeDescription(new TypeDescription(GeneralAccount.class, generalAccountTag));
    representer.addClassTag(GeneralAccount.class, generalAccountTag);

    Yaml yaml = new Yaml(constructor, representer);
    String dump = yaml.dump(customerAB);
    // System.out.println(dump);
    CustomerAB parsed = yaml.load(dump);
    assertNotNull(parsed);
  }

  public void testABProperty() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB_Property customerAB_property = new CustomerAB_Property();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
    general.add(generalAccount);
    general.add(supersaver);

    customerAB_property.acc = generalAccount;
    customerAB_property.bGeneral = general;

    Constructor constructor =
        new Constructor(YamlCreator.trustPrefixLoaderOptions("org.yaml.snakeyaml"));
    Representer representer = new Representer(new DumperOptions());

    Yaml yaml = new Yaml(constructor, representer);
    String dump = yaml.dump(customerAB_property);
    // System.out.println(dump);
    CustomerAB_Property parsed = yaml.load(dump);
    assertNotNull(parsed);
  }

  public void testABPropertyWithCustomTag() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB_Property customerAB_property = new CustomerAB_Property();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
    general.add(generalAccount);
    general.add(supersaver);

    customerAB_property.acc = generalAccount;
    customerAB_property.bGeneral = general;

    Constructor constructor =
        new Constructor(YamlCreator.trustPrefixLoaderOptions("org.yaml.snakeyaml"));
    Representer representer = new Representer(new DumperOptions());

    Tag generalAccountTag = new Tag("!GA");
    constructor.addTypeDescription(new TypeDescription(GeneralAccount.class, generalAccountTag));
    representer.addClassTag(GeneralAccount.class, generalAccountTag);

    Yaml yaml = new Yaml(constructor, representer);
    String dump = yaml.dump(customerAB_property);
    // System.out.println(dump);
    CustomerAB_Property parsed = yaml.load(dump);
    assertNotNull(parsed);
  }

  public void testABwithJavaBeanHelpers() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB customerAB = new CustomerAB();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
    general.add(generalAccount);
    general.add(supersaver);

    customerAB.aAll = all;
    customerAB.bGeneral = general;

    Yaml yaml = new Yaml();
    String dump2 = yaml.dumpAsMap(customerAB);
    // System.out.println(dump2);
    Yaml loader = YamlCreator.allowClassPrefix("org.yaml.snakeyaml");
    CustomerAB parsed = loader.loadAs(dump2, CustomerAB.class);
    assertNotNull(parsed);
  }

  public void testAB_asMapValue() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB_MapValue customerAB_mapValue = new CustomerAB_MapValue();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    Map<String, GeneralAccount> generalMap = new HashMap<String, GeneralAccount>();
    generalMap.put(generalAccount.name, generalAccount);
    generalMap.put(supersaver.name, supersaver);

    customerAB_mapValue.aAll = all;
    customerAB_mapValue.bGeneralMap = generalMap;

    Yaml yaml = YamlCreator.allowClassPrefix("org.yaml.snakeyaml");
    String dump = yaml.dump(customerAB_mapValue);
    // System.out.println(dump);
    CustomerAB_MapValue parsed = yaml.load(dump);
    assertNotNull(parsed);
  }

  public void testAB_asMapKey() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerAB_MapKey customerAB_mapKey = new CustomerAB_MapKey();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    Map<GeneralAccount, String> generalMap = new HashMap<GeneralAccount, String>();
    generalMap.put(generalAccount, generalAccount.name);
    generalMap.put(supersaver, supersaver.name);

    customerAB_mapKey.aAll = all;
    customerAB_mapKey.bGeneralMap = generalMap;

    Yaml yaml = YamlCreator.allowClassPrefix("org.yaml.snakeyaml");
    String dump = yaml.dump(customerAB_mapKey);
    // System.out.println(dump);
    CustomerAB_MapKey parsed = yaml.load(dump);
    assertNotNull(parsed);
  }

  public void testBA() {
    SuperSaverAccount supersaver = new SuperSaverAccount();
    GeneralAccount generalAccount = new GeneralAccount();

    CustomerBA customerBA = new CustomerBA();
    ArrayList<Account> all = new ArrayList<Account>();
    all.add(supersaver);
    all.add(generalAccount);
    ArrayList<GeneralAccount> general = new ArrayList<GeneralAccount>();
    general.add(generalAccount);
    general.add(supersaver);

    customerBA.aGeneral = general;
    customerBA.bAll = all;

    Yaml yaml = YamlCreator.allowClassPrefix("org.yaml.snakeyaml");
    String dump = yaml.dump(customerBA);
    // System.out.println(dump);
    //
    CustomerBA parsed = yaml.load(dump);
    assertEquals(2, parsed.bAll.size());
    assertEquals(2, parsed.aGeneral.size());
    assertNotEquals(parsed.bAll, parsed.aGeneral);
    GeneralAccount[] array = parsed.aGeneral.toArray(new GeneralAccount[2]);
    assertEquals(GeneralAccount.class, array[0].getClass());
    assertEquals(SuperSaverAccount.class, array[1].getClass());
    assertEquals("SuperSaver", array[1].name);
  }
}
