// Path: src/main/java/com/google/gwt/resources/gss/ast/CssJavaExpressionNode.java
// public class CssJavaExpressionNode extends CssValueNode {
// 
//   public CssJavaExpressionNode(String expression) {
//     this(expression, null);
//   }
// 
//   public CssJavaExpressionNode(String expression, SourceCodeLocation sourceCodeLocation) {
//     super(expression, sourceCodeLocation);
//   }
// 
//   @Override
//   public CssValueNode deepCopy() {
//     return new CssJavaExpressionNode(getValue());
//   }
// 
//   @Override
//   public String toString() {
//     return "Java expression : " + getValue();
//   }
// }
// 
// Path: src/main/java/com/google/gwt/resources/gss/ast/CssRuntimeConditionalRuleNode.java
// public class CssRuntimeConditionalRuleNode extends CssConditionalRuleNode {
// 
//   public CssRuntimeConditionalRuleNode(CssConditionalRuleNode node,
//       @Nullable CssJavaExpressionNode condition) {
//     super(node.getType(), node.getName().deepCopy(), null,
//         node.getBlock() != null ? node.getBlock().deepCopy() : null);
//     setSourceCodeLocation(node.getSourceCodeLocation());
// 
//     if (condition != null) {
//       setRuntimeCondition(condition);
//     }
//   }
// 
//   /**
//    * Copy constructor.
//    *
//    * @param node
//    */
//   public CssRuntimeConditionalRuleNode(CssRuntimeConditionalRuleNode node) {
//     this(node, node.getRuntimeCondition());
//   }
// 
//   /**
//    * Can only be called after the node is completely built (meaning it has
//    * the condition set).
//    */
//   public CssJavaExpressionNode getRuntimeCondition() {
//     if (getType() == Type.ELSE) {
//       Preconditions.checkState(getParametersCount() == 0);
//       return null;
//     }
// 
//     Preconditions.checkState(getParametersCount() == 1);
//     return (CssJavaExpressionNode) this.getParameters().get(0);
//   }
// 
//   void setRuntimeCondition(CssJavaExpressionNode condition) {
//     Preconditions.checkState(getType() != Type.ELSE);
//     Preconditions.checkState(getParametersCount() <= 1);
//     this.setParameters(ImmutableList.<CssValueNode>of(condition));
//   }
// 
//   @Override
//   public CssConditionalRuleNode deepCopy() {
//     return new CssRuntimeConditionalRuleNode(this);
//   }
// }


import java.util.regex.Pattern;
import com.google.common.collect.Lists;
import com.google.common.css.compiler.ast.CssAtRuleNode.Type;
import com.google.common.css.compiler.ast.CssBooleanExpressionNode;
import com.google.common.css.compiler.ast.CssCompilerPass;
import com.google.common.css.compiler.ast.CssConditionalBlockNode;
import com.google.common.css.compiler.ast.CssConditionalRuleNode;
import com.google.common.css.compiler.ast.CssValueNode;
import com.google.common.css.compiler.ast.DefaultTreeVisitor;
import com.google.common.css.compiler.ast.MutatingVisitController;
import com.google.gwt.resources.gss.ast.CssJavaExpressionNode;
import com.google.gwt.resources.gss.ast.CssRuntimeConditionalRuleNode;
import java.util.List;
import java.util.regex.Matcher;
/*
 * Copyright 2014 Julien Dramaix.
 *
 * 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.google.gwt.resources.gss;



public class CreateRuntimeConditionalNodes extends DefaultTreeVisitor implements CssCompilerPass {
  private static final Pattern EVAL_FUNCTION = Pattern.compile("^eval\\([\"']([^\"']*)[\"']\\)$");

  private final MutatingVisitController visitController;

  public CreateRuntimeConditionalNodes(MutatingVisitController visitController) {
    this.visitController = visitController;
  }

  @Override
  public boolean enterConditionalBlock(CssConditionalBlockNode block) {
    // we have to visit all the CssConditionalRuleNode when we visit the CssConditionalBlockNode
    // parent node because we are going to replace CssConditionalRuleNode by another node and
    // unfortunately the visitController doesn't support to replace a CssConditionalRuleNode and
    // we have to do it manually. That implies that the new nodes won't be visited by the
    // visitor if we do that during the visit of the CssConditionalRuleNodes.

    // make a copy in order to avoid ConcurrentModificationException
    List<CssConditionalRuleNode> children = Lists.newArrayList(block.getChildren());
    for (CssConditionalRuleNode ruleNode : children) {
      manuallyVisitConditionalRule(ruleNode, block);
    }
    return true;
  }

  private void manuallyVisitConditionalRule(CssConditionalRuleNode node,
      CssConditionalBlockNode parent) {

    if (node.getType() != Type.ELSE) {
      CssBooleanExpressionNode nodeCondition = node.getCondition();
      String condition = extractRuntimeCondition(nodeCondition);

      if (condition != null) {
// Path: src/main/java/com/google/gwt/resources/gss/ast/CssJavaExpressionNode.java
// public class CssJavaExpressionNode extends CssValueNode {
// 
//   public CssJavaExpressionNode(String expression) {
//     this(expression, null);
//   }
// 
//   public CssJavaExpressionNode(String expression, SourceCodeLocation sourceCodeLocation) {
//     super(expression, sourceCodeLocation);
//   }
// 
//   @Override
//   public CssValueNode deepCopy() {
//     return new CssJavaExpressionNode(getValue());
//   }
// 
//   @Override
//   public String toString() {
//     return "Java expression : " + getValue();
//   }
// }
// 
// Path: src/main/java/com/google/gwt/resources/gss/ast/CssRuntimeConditionalRuleNode.java
// public class CssRuntimeConditionalRuleNode extends CssConditionalRuleNode {
// 
//   public CssRuntimeConditionalRuleNode(CssConditionalRuleNode node,
//       @Nullable CssJavaExpressionNode condition) {
//     super(node.getType(), node.getName().deepCopy(), null,
//         node.getBlock() != null ? node.getBlock().deepCopy() : null);
//     setSourceCodeLocation(node.getSourceCodeLocation());
// 
//     if (condition != null) {
//       setRuntimeCondition(condition);
//     }
//   }
// 
//   /**
//    * Copy constructor.
//    *
//    * @param node
//    */
//   public CssRuntimeConditionalRuleNode(CssRuntimeConditionalRuleNode node) {
//     this(node, node.getRuntimeCondition());
//   }
// 
//   /**
//    * Can only be called after the node is completely built (meaning it has
//    * the condition set).
//    */
//   public CssJavaExpressionNode getRuntimeCondition() {
//     if (getType() == Type.ELSE) {
//       Preconditions.checkState(getParametersCount() == 0);
//       return null;
//     }
// 
//     Preconditions.checkState(getParametersCount() == 1);
//     return (CssJavaExpressionNode) this.getParameters().get(0);
//   }
// 
//   void setRuntimeCondition(CssJavaExpressionNode condition) {
//     Preconditions.checkState(getType() != Type.ELSE);
//     Preconditions.checkState(getParametersCount() <= 1);
//     this.setParameters(ImmutableList.<CssValueNode>of(condition));
//   }
// 
//   @Override
//   public CssConditionalRuleNode deepCopy() {
//     return new CssRuntimeConditionalRuleNode(this);
//   }
// }


// Path: src/main/java/com/google/gwt/resources/gss/CreateRuntimeConditionalNodes.java
import java.util.regex.Pattern;
import com.google.common.collect.Lists;
import com.google.common.css.compiler.ast.CssAtRuleNode.Type;
import com.google.common.css.compiler.ast.CssBooleanExpressionNode;
import com.google.common.css.compiler.ast.CssCompilerPass;
import com.google.common.css.compiler.ast.CssConditionalBlockNode;
import com.google.common.css.compiler.ast.CssConditionalRuleNode;
import com.google.common.css.compiler.ast.CssValueNode;
import com.google.common.css.compiler.ast.DefaultTreeVisitor;
import com.google.common.css.compiler.ast.MutatingVisitController;
import com.google.gwt.resources.gss.ast.CssJavaExpressionNode;
import com.google.gwt.resources.gss.ast.CssRuntimeConditionalRuleNode;
import java.util.List;
import java.util.regex.Matcher;

/*
 * Copyright 2014 Julien Dramaix.
 *
 * 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.google.gwt.resources.gss;



public class CreateRuntimeConditionalNodes extends DefaultTreeVisitor implements CssCompilerPass {
  private static final Pattern EVAL_FUNCTION = Pattern.compile("^eval\\([\"']([^\"']*)[\"']\\)$");

  private final MutatingVisitController visitController;

  public CreateRuntimeConditionalNodes(MutatingVisitController visitController) {
    this.visitController = visitController;
  }

  @Override
  public boolean enterConditionalBlock(CssConditionalBlockNode block) {
    // we have to visit all the CssConditionalRuleNode when we visit the CssConditionalBlockNode
    // parent node because we are going to replace CssConditionalRuleNode by another node and
    // unfortunately the visitController doesn't support to replace a CssConditionalRuleNode and
    // we have to do it manually. That implies that the new nodes won't be visited by the
    // visitor if we do that during the visit of the CssConditionalRuleNodes.

    // make a copy in order to avoid ConcurrentModificationException
    List<CssConditionalRuleNode> children = Lists.newArrayList(block.getChildren());
    for (CssConditionalRuleNode ruleNode : children) {
      manuallyVisitConditionalRule(ruleNode, block);
    }
    return true;
  }

  private void manuallyVisitConditionalRule(CssConditionalRuleNode node,
      CssConditionalBlockNode parent) {

    if (node.getType() != Type.ELSE) {
      CssBooleanExpressionNode nodeCondition = node.getCondition();
      String condition = extractRuntimeCondition(nodeCondition);

      if (condition != null) {
        CssJavaExpressionNode newNode = new CssJavaExpressionNode(condition,