Package com.github.sommeri.less4j.core.compiler.selectors

Source Code of com.github.sommeri.less4j.core.compiler.selectors.SelectorsComparatorForExtend

package com.github.sommeri.less4j.core.compiler.selectors;

import java.util.ArrayList;
import java.util.List;

import com.github.sommeri.less4j.core.ast.ASTCssNode;
import com.github.sommeri.less4j.core.ast.Selector;
import com.github.sommeri.less4j.core.ast.SelectorPart;
import com.github.sommeri.less4j.core.problems.BugHappened;
import com.github.sommeri.less4j.utils.ArraysUtils;
import com.github.sommeri.less4j.utils.ListsComparator;
import com.github.sommeri.less4j.utils.ListsComparator.MatchMarker;

public class SelectorsComparatorForExtend {

  private SelectorsComparatorUtils utils = new SelectorsComparatorUtils();
  private ListsComparator listsComparator = new ListsComparator();

  private ElementSubsequentComparator elementSubsequentComparator;
  private SimpleSelectorComparator simpleSelectorComparator;
  private SelectorPartComparator selectorPartsComparator;

  public SelectorsComparatorForExtend(GeneralComparatorForExtend generalComparator) {
    this.elementSubsequentComparator = new ElementSubsequentComparator(generalComparator, utils);
    this.simpleSelectorComparator = new SimpleSelectorComparator(elementSubsequentComparator, utils);
    this.selectorPartsComparator = new SelectorPartComparator(simpleSelectorComparator);
  }

  public boolean equals(Selector first, Selector second) {
    List<SelectorPart> firstParts = first.getParts();
    List<SelectorPart> secondParts = second.getParts();
    return listsComparator.equals(firstParts, secondParts, selectorPartsComparator);
  }

  public boolean contains(Selector lookFor, Selector inSelector) {
    List<SelectorPart> lookForParts = lookFor.getParts();
    List<SelectorPart> inSelectorParts = inSelector.getParts();

    return containsInList(lookForParts, inSelectorParts) || containsEmbedded(lookForParts, inSelectorParts);
  }

  public Selector replace(Selector lookFor, Selector inSelector, Selector replaceBy) {
    List<SelectorPart> lookForParts = lookFor.getParts();
    List<SelectorPart> inSelectorParts = ArraysUtils.deeplyClonedList(inSelector.getParts());

    Selector result = new Selector(replaceBy.getUnderlyingStructure(), inSelectorParts);
    replaceInList(lookForParts, result, replaceBy.getParts());
    replaceEmbedded(lookForParts, result, replaceBy.getParts());
    return result;
  }

  private boolean containsInList(List<SelectorPart> lookForParts, List<SelectorPart> inSelectorParts) {
    boolean contains = listsComparator.contains(lookForParts, inSelectorParts, selectorPartsComparator);
    return contains;
  }

  private void replaceInList(List<SelectorPart> lookForParts, Selector inSelector, List<SelectorPart> originalReplaceBy) {
    List<SelectorPart> inSelectorParts = inSelector.getParts();
    SelectorPartsListBuilder builder = new SelectorPartsListBuilder();

    List<MatchMarker<SelectorPart>> matches = listsComparator.findMatches(lookForParts, inSelectorParts, selectorPartsComparator);
    if (matches.isEmpty() || originalReplaceBy == null || originalReplaceBy.isEmpty())
      return ;

    SelectorPart lastRemainder = null;
    MatchMarker<SelectorPart> previousMatch = null;
    for (MatchMarker<SelectorPart> currentMatch : matches) {
      SelectorPart firstMatch = currentMatch.getFirst();
      SelectorPart lastMatch = currentMatch.getLast();
     
      if (!inSelectorParts.contains(firstMatch) && (previousMatch==null || lastRemainder==null ||  previousMatch.getLast()!=currentMatch.getFirst())) { //particularly ugly condition
        previousMatch = currentMatch;
        continue ;
      }
      boolean prefixNeeded = true;
     
      if (!inSelectorParts.contains(firstMatch) && lastRemainder!=null) { //particularly ugly code
        firstMatch = ArraysUtils.last(builder.getParts());
        prefixNeeded = false;
      }
     
      previousMatch = currentMatch;
      List<SelectorPart> replaceBy = ArraysUtils.deeplyClonedList(originalReplaceBy);

      if (firstMatch == lastMatch) {
        if (lookForParts.size() != 1)
          throw new BugHappened("Impossible state happened.", lookForParts.isEmpty() ? null : lookForParts.get(0));

        List<SelectorPart> replaceInside = replaceInsidePart(lookForParts.get(0), lastMatch, replaceBy);
        ArraysUtils.replace(lastMatch, inSelectorParts, replaceInside);
      } else {
        if (prefixNeeded)
          builder.addUpTo(inSelectorParts, firstMatch);
        ArraysUtils.chopFirst(inSelectorParts); // now we are chopping firstMatch

        SelectorPart firstRemainder = selectorPartsComparator.cutSuffix(lookForParts.get(0), firstMatch);
        if (firstRemainder != null) {
          if (prefixNeeded)
            builder.add(firstRemainder);
          builder.directlyAttach(replaceBy);
        } else {
          builder.addAll(replaceBy);
        }

        removeFromParent(ArraysUtils.chopUpTo(inSelectorParts, lastMatch));
        ArraysUtils.chopFirst(inSelectorParts); // now we are chopping lastMatch

        lastRemainder = selectorPartsComparator.cutPrefix(ArraysUtils.last(lookForParts), lastMatch);
        builder.directlyAttachNonNull(lastRemainder);
      }
    }

    builder.addAll(inSelectorParts);
    inSelector.setParts(builder.getParts());
    inSelector.configureParentToAllChilds();
  }

  private List<SelectorPart> replaceInsidePart(SelectorPart lookFor, SelectorPart inside, List<SelectorPart> replaceBy) {
    SelectorPart[] split = selectorPartsComparator.splitOn(lookFor, inside);
    SelectorPartsListBuilder builder = new SelectorPartsListBuilder();
    if (split.length > 0) {
      builder.directlyAttachNonNull(split[0]);
      for (int i = 1; i < split.length; i++) {
        builder.directlyAttach(ArraysUtils.deeplyClonedList(replaceBy));
        builder.directlyAttachNonNull(split[i]);
      }
    }
    return builder.getParts();
  }

  private void removeFromParent(List<SelectorPart> removeThese) {
    for (SelectorPart elementSubsequent : removeThese) {
      elementSubsequent.setParent(null);
    }
    removeThese.clear();
  }

  private boolean containsEmbedded(List<SelectorPart> lookFor, List<SelectorPart> inSelectors) {
    for (SelectorPart inside : inSelectors) {
      if (containsEmbedded(lookFor, inside))
        return true;
    }
    return false;
  }

  private boolean containsEmbedded(List<SelectorPart> lookFor, ASTCssNode inside) {
    for (ASTCssNode kid : inside.getChilds()) {
      if (containsEmbedded(lookFor, kid))
        return true;

      switch (kid.getType()) {
      case SELECTOR:
        Selector kidSelector = (Selector) kid;
        if (containsInList(lookFor, kidSelector.getParts()))
          return true;

      default:
        break;
      }
    }
    return false;
  }

  private void replaceEmbedded(List<SelectorPart> lookFor, ASTCssNode inside, List<SelectorPart> originalReplaceBy) {
    for (ASTCssNode kid : inside.getChilds()) {
      replaceEmbedded(lookFor, kid, originalReplaceBy);
      switch (kid.getType()) {
      case SELECTOR:
        Selector kidSelector = (Selector) kid;
        replaceInList(lookFor, kidSelector, originalReplaceBy);
      default:
        break;
      }
     
    }
  }

}

class SelectorPartsListBuilder {

  private SelectorsManipulator manipulator = new SelectorsManipulator();
  private List<SelectorPart> newInSelectorParts = new ArrayList<SelectorPart>();

  public SelectorPartsListBuilder() {
  }

  public List<SelectorPart> getParts() {
    return newInSelectorParts;
  }

  public void directlyAttachNonNull(SelectorPart part) {
    if (part != null)
      directlyAttach(part);
  }

  public void directlyAttach(SelectorPart part) {
    if (newInSelectorParts.isEmpty()) {
      add(part);
    } else {
      SelectorPart tail = ArraysUtils.last(newInSelectorParts);
      manipulator.directlyJoinParts(tail, part);
    }
  }

  public void directlyAttach(List<SelectorPart> list) {
    if (!newInSelectorParts.isEmpty()) {
      SelectorPart tail = ArraysUtils.last(newInSelectorParts);
      SelectorPart firstReplaceBy = list.remove(0);
      manipulator.directlyJoinParts(tail, firstReplaceBy);
    }
    addAll(list);
  }

  public void addAll(List<SelectorPart> list) {
    newInSelectorParts.addAll(list);
  }

  public void addNonNull(SelectorPart part) {
    if (part != null)
      add(part);
  }

  public void add(SelectorPart part) {
    newInSelectorParts.add(part);
  }

  public void addUpTo(List<SelectorPart> inSelectorParts, SelectorPart firstMatch) {
    newInSelectorParts.addAll(ArraysUtils.chopUpTo(inSelectorParts, firstMatch));
  }

  @Override
  public String toString() {
    return newInSelectorParts.toString();
  }

}
TOP

Related Classes of com.github.sommeri.less4j.core.compiler.selectors.SelectorsComparatorForExtend

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.