All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.phloc.html.js.builder.AbstractJSBlock Maven / Gradle / Ivy

There is a newer version: 4.4.9
Show newest version
/**
 * Copyright (C) 2006-2015 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * 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 com.phloc.html.js.builder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.phloc.commons.GlobalDebug;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.CodingStyleguideUnaware;
import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.OverrideOnDemand;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.annotations.ReturnsMutableObject;
import com.phloc.commons.collections.ContainerHelper;
import com.phloc.commons.equals.EqualsUtils;
import com.phloc.commons.hash.HashCodeGenerator;
import com.phloc.commons.math.MathHelper;
import com.phloc.commons.state.EChange;
import com.phloc.commons.string.ToStringGenerator;
import com.phloc.html.js.IJSCodeProvider;
import com.phloc.html.js.provider.CollectingJSCodeProvider;
import com.phloc.json.IJSON;

/**
 * A JS block. It contains a list of statements and declarations.
 *
 * @author Philip Helger
 */
@CodingStyleguideUnaware
public abstract class AbstractJSBlock implements IJSFunctionContainer
{
  private static final Logger s_aLogger = LoggerFactory.getLogger (AbstractJSBlock.class);

  /**
   * List of the content of this block
   */
  private final List  m_aObjs = new ArrayList  ();

  /**
   * Named map of all declarations
   */
  private final Map  m_aDecls = new HashMap  ();

  /**
   * Current position. Must be ≥ 0.
   */
  private int m_nPos = 0;

  /**
   * Constructor
   */
  public AbstractJSBlock ()
  {}

  /**
   * Removes a declaration from this package.
   *
   * @param sName
   *        Name to remove
   * @return Never null.
   */
  @Nonnull
  public EChange removeByName (final String sName)
  {
    final IJSDeclaration aDecl = this.m_aDecls.remove (sName);
    if (aDecl == null)
      return EChange.UNCHANGED;
    this.m_aObjs.remove (aDecl);
    return EChange.CHANGED;
  }

  @Nonnull
  @ReturnsMutableCopy
  public List  declarations ()
  {
    return ContainerHelper.newList (this.m_aDecls.values ());
  }

  /**
   * Gets a reference to the already created {@link JSDefinedClass}.
   *
   * @param sName
   *        Name to search
   * @return null If the object is not yet created.
   */
  @Nullable
  public IJSDeclaration getDeclaration (@Nullable final String sName)
  {
    return this.m_aDecls.get (sName);
  }

  /**
   * Checks if a given name is already defined as a class/interface
   *
   * @param sName
   *        Name to search
   * @return true if the passed variable is contained
   */
  public boolean isDeclared (@Nullable final String sName)
  {
    return this.m_aDecls.containsKey (sName);
  }

  /**
   * @return true if this block is empty and does not contain any
   *         statement.
   */
  public boolean isEmpty ()
  {
    return this.m_aObjs.isEmpty ();
  }

  @Nonnegative
  public int memberCount ()
  {
    return this.m_aObjs.size ();
  }

  @Nonnull
  @ReturnsMutableObject (reason = "speed")
  List  directMembers ()
  {
    // ESCA-JAVA0259:
    return this.m_aObjs;
  }

  @Nonnull
  @ReturnsMutableCopy
  public List  members ()
  {
    return ContainerHelper.newList (this.m_aObjs);
  }

  /**
   * Remove all contents of the block. Sets the position to 0.
   *
   * @return this
   */
  @Nonnull
  public AbstractJSBlock clear ()
  {
    this.m_aObjs.clear ();
    this.m_aDecls.clear ();
    this.m_nPos = 0;
    return this;
  }

  /**
   * Called when a declaration is added
   *
   * @param aDeclaration
   *        The added declaration. Never null.
   */
  @OverrideOnDemand
  protected void onAddDeclaration (@Nonnull final IJSDeclaration aDeclaration)
  {}

  @Nonnull
  public final  T addDeclaration (@Nonnull final T aDeclaration) throws JSNameAlreadyExistsException
  {
    ValueEnforcer.notNull (aDeclaration, "Declaration");

    final String sName = aDeclaration.name ();
    final IJSDeclaration aOldDecl = this.m_aDecls.get (sName);
    if (aOldDecl != null)
      throw new JSNameAlreadyExistsException (aOldDecl);
    this.m_aObjs.add (this.m_nPos, aDeclaration);
    this.m_aDecls.put (sName, aDeclaration);
    this.m_nPos++;
    onAddDeclaration (aDeclaration);
    return aDeclaration;
  }

  @Nonnull
  public final  T addStatement (@Nonnull final T aStatement)
  {
    ValueEnforcer.notNull (aStatement, "Statement");

    this.m_aObjs.add (this.m_nPos, aStatement);
    this.m_nPos++;
    return aStatement;
  }

  /**
   * Gets the current position to which new statements will be inserted. For
   * example if the value is 0, newly created instructions will be inserted at
   * the very beginning of the block.
   *
   * @return The current position
   * @see #pos(int)
   */
  @Nonnegative
  public int pos ()
  {
    return this.m_nPos;
  }

  /**
   * Sets the current position.
   *
   * @param nNewPos
   *        New position to use
   * @return the old value of the current position.
   * @throws IllegalArgumentException
   *         if the new position value is illegal.
   * @see #pos()
   */
  @Nonnegative
  public int pos (@Nonnegative final int nNewPos)
  {
    ValueEnforcer.isBetweenInclusive (nNewPos, "NewPos", 0, this.m_aObjs.size ());
    final int nOldPos = this.m_nPos;
    this.m_nPos = nNewPos;
    return nOldPos;
  }

  /**
   * Sets the current position to the end of the block.
   *
   * @return the old value of the current position.
   * @see #pos()
   */
  @Nonnegative
  public int posEnd ()
  {
    return pos (this.m_aObjs.size ());
  }

  /**
   * Add a class to this package.
   *
   * @param sName
   *        Name of class to be added to this package
   * @return Newly generated class
   * @exception JSNameAlreadyExistsException
   *            When the specified class/interface was already created.
   */
  @Nonnull
  public JSDefinedClass _class (@Nonnull @Nonempty final String sName) throws JSNameAlreadyExistsException
  {
    final JSDefinedClass aDefinedClass = new JSDefinedClass (sName);
    return addDeclaration (aDefinedClass);
  }

  /**
   * @param aType
   *        The type to be instantiated
   * @return A "new type" invocation object
   */
  @Nonnull
  public JSInvocation _new (@Nonnull final AbstractJSType aType)
  {
    ValueEnforcer.notNull (aType, "Type");

    return aType._new ();
  }

  @Override
  @Nonnull
  public JSFunction function (@Nonnull final String sName) throws JSNameAlreadyExistsException
  {
    return function (null, sName);
  }

  /**
   * Add a function to this package.
   *
   * @param aType
   *        Optional return type
   * @param sName
   *        Name of function to be added to this package
   * @return Newly generated function
   * @exception JSNameAlreadyExistsException
   *            When the specified function was already created.
   */
  @Override
  @Nonnull
  public JSFunction function (@Nullable final AbstractJSType aType, @Nonnull @Nonempty final String sName) throws JSNameAlreadyExistsException
  {
    final JSFunction aFunction = new JSFunction (aType, sName);
    return addDeclaration (aFunction);
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName) throws JSNameAlreadyExistsException
  {
    return var (null, sName, null);
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param bInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final boolean bInitValue) throws JSNameAlreadyExistsException
  {
    return var (null, sName, JSExpr.lit (bInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param cInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final char cInitValue) throws JSNameAlreadyExistsException
  {
    return var (null, sName, JSExpr.lit (cInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param dInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final double dInitValue) throws JSNameAlreadyExistsException
  {
    return var (null, sName, JSExpr.lit (dInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param fInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final float fInitValue) throws JSNameAlreadyExistsException
  {
    return var (null, sName, JSExpr.lit (fInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param nInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final int nInitValue) throws JSNameAlreadyExistsException
  {
    return var (null, sName, JSExpr.lit (nInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param nInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, final long nInitValue) throws JSNameAlreadyExistsException
  {
    return var (null, sName, JSExpr.lit (nInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param sInitValue
   *        Initialization value for this variable.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, @Nullable final String sInitValue) throws JSNameAlreadyExistsException
  {
    return var (null, sName, sInitValue == null ? JSExpr.NULL : JSExpr.lit (sInitValue));
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param sName
   *        Name of the variable
   * @param aInitExpression
   *        Initialization expression for this variable. May be null.
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nonnull @Nonempty final String sName, @Nullable final IJSExpression aInitExpression) throws JSNameAlreadyExistsException
  {
    return var (null, sName, aInitExpression);
  }

  /**
   * Adds a local variable declaration to this block
   *
   * @param aType
   *        Type of the variable
   * @param sName
   *        Name of the variable
   * @return Newly generated {@link JSVar}
   * @throws JSNameAlreadyExistsException
   *         if the name is not unique
   */
  @Nonnull
  public JSVar var (@Nullable final AbstractJSType aType, @Nonnull @Nonempty final String sName) throws JSNameAlreadyExistsException
  {
    return var (aType, sName, null);
  }

  /**
   * Add a var to this block.
   *
   * @param aType
   *        optional type to use
   * @param sName
   *        Name of variable to be added to this package
   * @param aInitExpression
   *        the initial expression. May be null
   * @return Newly generated function
   * @exception JSNameAlreadyExistsException
   *            When the specified var was already created.
   */
  @Nonnull
  public JSVar var (@Nullable final AbstractJSType aType,
                    @Nonnull @Nonempty final String sName,
                    @Nullable final IJSExpression aInitExpression) throws JSNameAlreadyExistsException
  {
    final JSVar aVar = new JSVar (aType, sName, aInitExpression);
    return addDeclaration (aVar);
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull final JSAnonymousFunction aAnonFunction)
  {
    ValueEnforcer.notNull (aAnonFunction, "AnonFunction");

    return addStatement (aAnonFunction.invoke ());
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull final JSFunction aFunction)
  {
    ValueEnforcer.notNull (aFunction, "Function");

    return addStatement (aFunction.invoke ());
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull @Nonempty final String sFunctionName)
  {
    final JSInvocation aInvocation = new JSInvocation (sFunctionName);
    return addStatement (aInvocation);
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull @Nonempty final String sField, @Nonnull @Nonempty final String sMethodName)
  {
    final JSInvocation aInvocation = JSExpr.ref (sField).invoke (sMethodName);
    return addStatement (aInvocation);
  }

  @Nonnull
  public JSInvocation invoke (@Nonnull @Nonempty final String sField, @Nonnull final JSMethod aMethod)
  {
    final JSInvocation aInvocation = JSExpr.ref (sField).invoke (aMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates an invocation statement and adds it to this block.
   *
   * @param aExpr
   *        JExpression evaluating to the class or object upon which the named
   *        method will be invoked
   * @param sMethod
   *        Name of method to invoke
   * @return Newly generated {@link JSInvocation}
   */
  @Nonnull
  public JSInvocation invoke (@Nullable final IJSExpression aExpr, @Nonnull @Nonempty final String sMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aExpr, sMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates an invocation statement and adds it to this block.
   *
   * @param aExpr
   *        JExpression evaluating to the class or object upon which the method
   *        will be invoked
   * @param aMethod
   *        JMethod to invoke
   * @return Newly generated {@link JSInvocation}
   */
  @Nonnull
  public JSInvocation invoke (@Nullable final IJSExpression aExpr, @Nonnull final JSMethod aMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aExpr, aMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates a static invocation statement.
   *
   * @param aType
   *        Type to use
   * @param sMethod
   *        Method name to invoke
   * @return Never null.
   */
  @Nonnull
  public JSInvocation staticInvoke (@Nullable final AbstractJSClass aType, @Nonnull final String sMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aType, sMethod);
    return addStatement (aInvocation);
  }

  /**
   * Creates a static invocation statement.
   *
   * @param aType
   *        Type to use
   * @param aMethod
   *        Method to invoke
   * @return Never null.
   */
  @Nonnull
  public JSInvocation staticInvoke (@Nullable final AbstractJSClass aType, @Nonnull final JSMethod aMethod)
  {
    final JSInvocation aInvocation = new JSInvocation (aType, aMethod);
    return addStatement (aInvocation);
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final boolean bValue)
  {
    return assign (aLhs, JSExpr.lit (bValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final char cValue)
  {
    return assign (aLhs, JSExpr.lit (cValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    return assign (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    return assign (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    return assign (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    return assign (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final String sValue)
  {
    return assign (aLhs, sValue == null ? JSExpr.NULL : JSExpr.lit (sValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, @Nullable final IJSON aValue)
  {
    return assign (aLhs, aValue == null ? JSExpr.NULL : JSExpr.json (aValue));
  }

  @Nonnull
  public AbstractJSBlock assign (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (aLhs.assign (aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final char cValue)
  {
    return assignPlus (aLhs, JSExpr.lit (cValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No add with 0
    if (EqualsUtils.equals (dValue, 0))
      return this;
    if (dValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (dValue)));
    return assignPlus (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No add with 0
    if (EqualsUtils.equals (fValue, 0))
      return this;
    if (fValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (fValue)));
    return assignPlus (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No add with 0
    if (EqualsUtils.equals (nValue, 0))
      return this;
    if (nValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (nValue)));
    return assignPlus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No add with 0
    if (EqualsUtils.equals (nValue, 0))
      return this;
    if (nValue < 0)
      return assignMinus (aLhs, JSExpr.lit (MathHelper.abs (nValue)));
    return assignPlus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final String sValue)
  {
    return assignPlus (aLhs, JSExpr.lit (sValue));
  }

  @Nonnull
  public AbstractJSBlock assignPlus (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignPlus (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No subtract with 0
    if (EqualsUtils.equals (dValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No subtract with 0
    if (EqualsUtils.equals (fValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No subtract with 0
    if (EqualsUtils.equals (nValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No subtract with 0
    if (EqualsUtils.equals (nValue, 0))
      return this;
    return assignMinus (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMinus (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignMinus (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No multiply with 1
    if (EqualsUtils.equals (dValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No multiply with 1
    if (EqualsUtils.equals (fValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No multiply with 1
    if (EqualsUtils.equals (nValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No multiply with 1
    if (EqualsUtils.equals (nValue, 1))
      return this;
    return assignMultiply (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignMultiply (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignMultiply (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final double dValue)
  {
    // No divide by 1
    if (EqualsUtils.equals (dValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final float fValue)
  {
    // No divide by 1
    if (EqualsUtils.equals (fValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    // No divide by 1
    if (EqualsUtils.equals (nValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    // No divide by 1
    if (EqualsUtils.equals (nValue, 1))
      return this;
    return assignDivide (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignDivide (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignDivide (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock assignModulo (@Nonnull final IJSAssignmentTarget aLhs, final int nValue)
  {
    return assignModulo (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignModulo (@Nonnull final IJSAssignmentTarget aLhs, final long nValue)
  {
    return assignModulo (aLhs, JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock assignModulo (@Nonnull final IJSAssignmentTarget aLhs, @Nonnull final IJSExpression aExpr)
  {
    addStatement (JSExpr.assignModulo (aLhs, aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock incrPostfix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSIncrPostfix (aLhs));
    return this;
  }

  @Nonnull
  public AbstractJSBlock incrPrefix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSIncrPrefix (aLhs));
    return this;
  }

  @Nonnull
  public AbstractJSBlock decrPostfix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSDecrPostfix (aLhs));
    return this;
  }

  @Nonnull
  public AbstractJSBlock decrPrefix (@Nonnull final IJSAssignmentTarget aLhs)
  {
    addStatement (new JSDecrPrefix (aLhs));
    return this;
  }

  /**
   * Create a For statement and add it to this block
   *
   * @return Newly generated For statement
   */
  @Nonnull
  public JSForLoop _for ()
  {
    return addStatement (new JSForLoop ());
  }

  @Nonnull
  public JSForIn forIn (@Nonnull final JSVar aVar, @Nonnull final IJSExpression aCollection)
  {
    return addStatement (new JSForIn (aVar, aCollection));
  }

  @Nonnull
  public JSForIn forIn (@Nonnull @Nonempty final String sVarName, @Nonnull final IJSExpression aCollection)
  {
    return forIn (null, sVarName, aCollection);
  }

  @Nonnull
  public JSForIn forIn (@Nullable final AbstractJSType aVarType,
                        @Nonnull @Nonempty final String sVarName,
                        @Nonnull final IJSExpression aCollection)
  {
    return addStatement (new JSForIn (aVarType, sVarName, aCollection));
  }

  /**
   * Create a While statement and add it to this block
   *
   * @param aTest
   *        The while condition to use
   * @return Newly generated While statement
   */
  @Nonnull
  public JSWhileLoop _while (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSWhileLoop (aTest));
  }

  /**
   * Create a Do statement and add it to this block
   *
   * @return Newly generated Do statement
   */
  @Nonnull
  public JSDoLoop _do (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSDoLoop (aTest));
  }

  /**
   * Create a switch/case statement and add it to this block
   */
  @Nonnull
  public JSSwitch _switch (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSSwitch (aTest));
  }

  /**
   * Create a Try statement and add it to this block
   *
   * @return Newly generated Try statement
   */
  @Nonnull
  public JSTryBlock _try ()
  {
    return addStatement (new JSTryBlock ());
  }

  /**
   * Insert a delete aExpr; statement
   *
   * @param aExpr
   *        the expression to be deleted. May not be null.
   */
  @Nonnull
  public AbstractJSBlock delete (@Nonnull final IJSExpression aExpr)
  {
    addStatement (new JSDelete (aExpr));
    return this;
  }

  /**
   * Create a throw statement and add it to this block
   */
  @Nonnull
  public AbstractJSBlock _throw (@Nonnull final IJSExpression aExpr)
  {
    addStatement (new JSThrow (aExpr));
    return this;
  }

  @Nonnull
  public AbstractJSBlock debugger ()
  {
    addStatement (new JSDebugger ());
    return this;
  }

  /**
   * Create a label, which can be referenced from continue and
   * break statements.
   */
  @Nonnull
  public JSLabel label (@Nonnull @Nonempty final String sName)
  {
    return addStatement (new JSLabel (sName));
  }

  /**
   * Create an If statement and add it to this block
   *
   * @param aTest
   *        {@link IJSExpression} to be tested to determine branching
   * @return Newly generated conditional statement
   */
  @Nonnull
  public JSConditional _if (@Nonnull final IJSExpression aTest)
  {
    return addStatement (new JSConditional (aTest));
  }

  /**
   * Create a return statement and add it to this block
   */
  @Nonnull
  public AbstractJSBlock _return ()
  {
    return _return ((IJSExpression) null);
  }

  @Nonnull
  public AbstractJSBlock _return (final boolean bValue)
  {
    return _return (JSExpr.lit (bValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final char cValue)
  {
    return _return (JSExpr.lit (cValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final double dValue)
  {
    return _return (JSExpr.lit (dValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final float fValue)
  {
    return _return (JSExpr.lit (fValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final int nValue)
  {
    return _return (JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock _return (final long nValue)
  {
    return _return (JSExpr.lit (nValue));
  }

  @Nonnull
  public AbstractJSBlock _return (@Nullable final String sValue)
  {
    return _return (sValue == null ? JSExpr.NULL : JSExpr.lit (sValue));
  }

  @Nonnull
  public AbstractJSBlock _return (@Nullable final IJSON aValue)
  {
    return _return (aValue == null ? JSExpr.NULL : JSExpr.json (aValue));
  }

  /**
   * Create a return statement and add it to this block
   */
  @Nonnull
  public AbstractJSBlock _return (@Nullable final IJSExpression aExpr)
  {
    addStatement (new JSReturn (aExpr));
    return this;
  }

  /**
   * Create a sub-block and add it to this block
   *
   * @return The newly created block
   */
  @Nonnull
  public JSBlock block ()
  {
    return addStatement (new JSBlock (false, false));
  }

  @Nonnull
  public AbstractJSBlock comment (@Nonnull final String sComment)
  {
    addStatement (new JSCommentSingleLine (sComment));
    return this;
  }

  @Nonnull
  public AbstractJSBlock add (@Nonnull final IJSCodeProvider aJSCode)
  {
    if (aJSCode instanceof JSPackage)
    {
      // Avoid nested JSPackage
      for (final IJSCodeProvider aNestedJSCode : ((JSPackage) aJSCode).members ())
        add (aNestedJSCode);
    }
    else
      if (aJSCode instanceof CollectingJSCodeProvider)
      {
        // Flatten CollectingJSCodeProvider
        for (final IJSCodeProvider aNestedJSCode : ((CollectingJSCodeProvider) aJSCode).getAll ())
          add (aNestedJSCode);
      }
      else
      {
        if (GlobalDebug.isDebugMode ())
          if (!(aJSCode instanceof IJSDeclaration) && !(aJSCode instanceof IJSStatement))
            s_aLogger.warn ("Adding untyped IJSCodeProvider of class " + aJSCode.getClass ().getName () + " to JSBlock");

        this.m_aObjs.add (this.m_nPos, aJSCode);
        this.m_nPos++;
      }
    return this;
  }

  @Nonnull
  public AbstractJSBlock add (@Nonnull final IJSStatement aStatement)
  {
    addStatement (aStatement);
    return this;
  }

  @Override
  public boolean equals (final Object o)
  {
    if (o == this)
      return true;
    if (o == null || !getClass ().equals (o.getClass ()))
      return false;
    final AbstractJSBlock rhs = (AbstractJSBlock) o;
    return this.m_aObjs.equals (rhs.m_aObjs) && this.m_aDecls.equals (rhs.m_aDecls) && this.m_nPos == rhs.m_nPos;
  }

  @Override
  public int hashCode ()
  {
    return new HashCodeGenerator (this).append (this.m_aObjs)
                                       .append (this.m_aDecls)
                                       .append (this.m_nPos)
                                       .getHashCode ();
  }

  @Override
  public String toString ()
  {
    return new ToStringGenerator (this).appendIfNotEmpty ("objs", this.m_aObjs)
                                       .appendIfNotEmpty ("decls", this.m_aDecls)
                                       .append ("pos", this.m_nPos)
                                       .toString ();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy