/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.33.0.6934.a386b0a58 modeling language!*/

package example;
import java.util.*;

// line 4 "../ToJsonTest_1.ump"
public class Person
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //Person Attributes
  private String name;

  //Person Associations
  private List<Address> addresses;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public Person(String aName)
  {
    name = aName;
    addresses = new ArrayList<Address>();
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setName(String aName)
  {
    boolean wasSet = false;
    name = aName;
    wasSet = true;
    return wasSet;
  }

  public String getName()
  {
    return name;
  }
  /* Code from template association_GetMany */
  public Address getAddress(int index)
  {
    Address aAddress = addresses.get(index);
    return aAddress;
  }

  public List<Address> getAddresses()
  {
    List<Address> newAddresses = Collections.unmodifiableList(addresses);
    return newAddresses;
  }

  public int numberOfAddresses()
  {
    int number = addresses.size();
    return number;
  }

  public boolean hasAddresses()
  {
    boolean has = addresses.size() > 0;
    return has;
  }

  public int indexOfAddress(Address aAddress)
  {
    int index = addresses.indexOf(aAddress);
    return index;
  }
  /* Code from template association_MinimumNumberOfMethod */
  public static int minimumNumberOfAddresses()
  {
    return 0;
  }
  /* Code from template association_AddManyToOne */
  public Address addAddress(String aStreet)
  {
    return new Address(aStreet, this);
  }

  public boolean addAddress(Address aAddress)
  {
    boolean wasAdded = false;
    if (addresses.contains(aAddress)) { return false; }
    Person existingPerson = aAddress.getPerson();
    boolean isNewPerson = existingPerson != null && !this.equals(existingPerson);
    if (isNewPerson)
    {
      aAddress.setPerson(this);
    }
    else
    {
      addresses.add(aAddress);
    }
    wasAdded = true;
    return wasAdded;
  }

  public boolean removeAddress(Address aAddress)
  {
    boolean wasRemoved = false;
    //Unable to remove aAddress, as it must always have a person
    if (!this.equals(aAddress.getPerson()))
    {
      addresses.remove(aAddress);
      wasRemoved = true;
    }
    return wasRemoved;
  }
  /* Code from template association_AddIndexControlFunctions */
  public boolean addAddressAt(Address aAddress, int index)
  {  
    boolean wasAdded = false;
    if(addAddress(aAddress))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfAddresses()) { index = numberOfAddresses() - 1; }
      addresses.remove(aAddress);
      addresses.add(index, aAddress);
      wasAdded = true;
    }
    return wasAdded;
  }

  public boolean addOrMoveAddressAt(Address aAddress, int index)
  {
    boolean wasAdded = false;
    if(addresses.contains(aAddress))
    {
      if(index < 0 ) { index = 0; }
      if(index > numberOfAddresses()) { index = numberOfAddresses() - 1; }
      addresses.remove(aAddress);
      addresses.add(index, aAddress);
      wasAdded = true;
    } 
    else 
    {
      wasAdded = addAddressAt(aAddress, index);
    }
    return wasAdded;
  }

  public void delete()
  {
    for(int i=addresses.size(); i > 0; i--)
    {
      Address aAddress = addresses.get(i - 1);
      aAddress.delete();
    }
  }


  public String toString()
  {
    return super.toString() + "["+
            "name" + ":" + getName()+ "]";
  }
      
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */  
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");

      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
      // When an object has not already been visited, output its details
      toJsonOutput.append(",\n");
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("name");
          toJsonOutput.append("\" : \"");
          toJsonOutput.append(""+getName()+ "");
          toJsonOutput.append("\"");
          toJsonOutput.append(",\n");
      haveOutputItem = false;
      haveOutputItem = false;
         if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
          toJsonOutput.append(indent);
            toJsonOutput.append("  \"");
            toJsonOutput.append("addresses");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : [");
            toJsonOutput.append("\n");
            haveOutputItem = false;
            for (Address anItem :getAddresses()){
              if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
              toJsonOutput.append(indent+"{");
              toJsonOutput.append("\n");
              anItem.toJsonHelper(toJsonOutput, visitedList,nestLevel+2,true);
              toJsonOutput.append("\n");
              toJsonOutput.append(indent+"}");
              haveOutputItem=true;
            }
            toJsonOutput.append("\n");    
            toJsonOutput.append(indent+"]");
            toJsonOutput.append("\n"); 
            haveOutputItem=true;     
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
}
/*PLEASE DO NOT EDIT THIS CODE*/
/*This code was generated using the UMPLE 1.33.0.6934.a386b0a58 modeling language!*/

package example;
import java.util.HashSet;

// line 8 "../ToJsonTest_1.ump"
public class Address
{

  //------------------------
  // MEMBER VARIABLES
  //------------------------

  //Address Attributes
  private String street;

  //Address Associations
  private Person person;

  //------------------------
  // CONSTRUCTOR
  //------------------------

  public Address(String aStreet, Person aPerson)
  {
    street = aStreet;
    boolean didAddPerson = setPerson(aPerson);
    if (!didAddPerson)
    {
      throw new RuntimeException("Unable to create address due to person. See http://manual.umple.org?RE002ViolationofAssociationMultiplicity.html");
    }
  }

  //------------------------
  // INTERFACE
  //------------------------

  public boolean setStreet(String aStreet)
  {
    boolean wasSet = false;
    street = aStreet;
    wasSet = true;
    return wasSet;
  }

  public String getStreet()
  {
    return street;
  }
  /* Code from template association_GetOne */
  public Person getPerson()
  {
    return person;
  }
  /* Code from template association_SetOneToMany */
  public boolean setPerson(Person aPerson)
  {
    boolean wasSet = false;
    if (aPerson == null)
    {
      return wasSet;
    }

    Person existingPerson = person;
    person = aPerson;
    if (existingPerson != null && !existingPerson.equals(aPerson))
    {
      existingPerson.removeAddress(this);
    }
    person.addAddress(this);
    wasSet = true;
    return wasSet;
  }

  public void delete()
  {
    Person placeholderPerson = person;
    this.person = null;
    if(placeholderPerson != null)
    {
      placeholderPerson.removeAddress(this);
    }
  }


  public String toString()
  {
    return super.toString() + "["+
            "street" + ":" + getStreet()+ "]" + System.getProperties().getProperty("line.separator") +
            "  " + "person = "+(getPerson()!=null?Integer.toHexString(System.identityHashCode(getPerson())):"null");
  }
      
  /*
  * Generate Json for this object and connected objects visited objects to enable avoidance of infinite loops
  *
  * @param toJsonOutput  Output is aded to this as the network of objects is traversed
  * @param visitedList  Every concrete object visited is added so we don't re-outpu
  * @param nestLevel    As we output deeper objects, indent them more
  * @param atConcreteClass false when we are recursing to a superclass
  *     so we get the superclass data
  * @return whether or not anything was output (so we can tell whether we need to output a comma)
  */  
  public String toJson()
  {
    HashSet<Object> visitedList = new HashSet<Object>();
    StringBuilder toJsonOutput = new StringBuilder();
    toJsonOutput.append("{\n");
    this.toJsonHelper(toJsonOutput, visitedList,1,true);
    toJsonOutput.append("\n}");
    return(toJsonOutput.toString());
  }
   
  public boolean toJsonHelper(StringBuilder toJsonOutput, HashSet<Object> visitedList, int nestLevel, boolean atConcreteClass){
      
      String indent = "  ".repeat(nestLevel);
      boolean alreadyVisited = false;
      boolean haveOutputItem = false;
      
    if(atConcreteClass) {
      // This will not be true in a super call; output header
      toJsonOutput.append(indent+"\""+this.toString().split("@")[0]+ "\" : {\n"+indent+ "  \"umpleObjectID\" : \""+System.identityHashCode(this)+"\"");

      // Check if we have already visited this object. If so we will not output details
      alreadyVisited = visitedList.contains(this);
      if(!alreadyVisited) {
        visitedList.add(this);
      }
    }
    
    // There is no superclass of this class
    if(alreadyVisited) {
      toJsonOutput.append("\n");
    }
    else {
      // Check if this class has a superclass. If it does, we make a call to output superclass content 
      // This will keep calling super so the topmost attributes and associations appear first
      // When an object has not already been visited, output its details
      toJsonOutput.append(",\n");
          toJsonOutput.append(indent);
          toJsonOutput.append("  \"");
          toJsonOutput.append("street");
          toJsonOutput.append("\" : \"");
          toJsonOutput.append(""+getStreet()+ "");
          toJsonOutput.append("\"");
          toJsonOutput.append(",\n");
      haveOutputItem = false;
      haveOutputItem = false;
         if(haveOutputItem) {
                toJsonOutput.append(",\n");
              }
          toJsonOutput.append(indent);
            toJsonOutput.append("\n");
            toJsonOutput.append("  \"");
            toJsonOutput.append("person");
            toJsonOutput.append("\"");
            toJsonOutput.append(" : ");
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"{");
            toJsonOutput.append("\n");Person anotherItem = getPerson();
            anotherItem.toJsonHelper(toJsonOutput, visitedList, nestLevel+2, true);
            toJsonOutput.append("\n");
            toJsonOutput.append(indent+"}");
            haveOutputItem=true;     
          toJsonOutput.append(indent+"  \n");
    }
    // Finalize the output of the concrete class
    if(atConcreteClass) {
      if(!alreadyVisited) {
        toJsonOutput.append("\n");
      }
      toJsonOutput.append(indent+"}");
    }
    haveOutputItem = true;
    return haveOutputItem;
  }

  
}