package org.kefirsf.bb.proc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
/**
* The bbcode class
*
* @author Kefir
*/
public class ProcCode implements Comparable<ProcCode> {
private final Logger logGenerate = LoggerFactory.getLogger(BBProcessor.LOGGER_GENERATE);
private final Logger logContext = LoggerFactory.getLogger(BBProcessor.LOGGER_CONTEXT);
/**
* template for build result char sequence
*/
private final ProcTemplate template;
/**
* Pattern for parsing code
*/
private final List<ProcPattern> patterns;
/**
* Priority. If priority higher then code be checking early.
*/
private final int priority;
/**
* The code name.
*/
private final String name;
/**
* Do show variables outside the code?
*/
private final boolean transparent;
/**
* Create the bb-code with priority
* @param patterns pattern to parse the source text
* @param template template to build target text
* @param name name of code
* @param priority priority. If priority higher then code be checking early.
* @param transparent Do show variables outside the code?
*/
public ProcCode(List<ProcPattern> patterns, ProcTemplate template, String name, int priority, boolean transparent) {
this.template = template;
this.priority = priority;
this.name = name;
this.patterns = patterns;
this.transparent = transparent;
}
/**
* Parse bb-code
*
* Before invocation suspicious method must be call
*
* @param context the bb-processing context
* @return true - if parse source
* false - if can't parse code
* @throws NestingException if nesting is too big.
*/
public boolean process(Context context) throws NestingException {
for(ProcPattern pattern: patterns){
Context codeContext = new Context(context);
if (pattern.parse(codeContext)) {
if(transparent) {
codeContext.mergeWithParent();
}
template.generate(codeContext);
if(logContext.isTraceEnabled()){
for(Map.Entry<String, CharSequence> entry:context.getAttributes().entrySet()){
logContext.trace("Context: {} = {}", entry.getKey(), entry.getValue());
}
}
if(logGenerate.isTraceEnabled()){
logGenerate.trace("Generated text: {}", codeContext.getTarget());
}
return true;
}
}
return false;
}
/**
* Check if next sequence can be parsed with this code.
* It's most called method in this project.
*
* @param context current context
* @return true - if next sequence can be parsed with this code;
* false - only if next sequence can't be parsed with this code.
*/
public boolean suspicious(Context context) {
for(ProcPattern pattern:patterns){
if(pattern.suspicious(context)){
return true;
}
}
return false;
}
/**
* Compare by priorities
*/
public int compareTo(ProcCode code) {
return this.priority - code.priority;
}
public boolean startsWithConstant(){
for(ProcPattern pattern: patterns){
if(!pattern.startsWithConstant()){
return false;
}
}
return true;
}
@SuppressWarnings("RedundantIfStatement")
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProcCode procCode = (ProcCode) o;
if (name != null ? !name.equals(procCode.name) : procCode.name != null) return false;
return true;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
public boolean containsCheck() {
for(ProcPattern pattern: patterns){
if(pattern.hasCheck()){
return true;
}
}
return false;
}
}