package input.parser.impl;
import input.model.Section;
import input.model.impl.CompositeSection;
import input.model.impl.UrlSection;
import input.parser.SadParser;
import input.xmltemplatereader.TemplateStructure;
import input.xmltemplatereader.XmlReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import net.htmlparser.jericho.Attribute;
import net.htmlparser.jericho.Source;
public class WikiParser implements SadParser {
private static final String SLASH = "/";
private String urlBase;
private int lastIndexValid;
public Section getSad(String path, String urlWiki) {
URL url= null;
try {
url= new URL(urlWiki);
} catch (MalformedURLException e) {
e.printStackTrace();
}
urlBase= url.getProtocol()+"://"+url.getHost();
Source source=null;
try {
source = new Source(url);
} catch (IOException e) {
e.printStackTrace();
}
CompositeSection document= generateStructure(source,path);
return document;
}
private CompositeSection generateStructure(Source source,String templatePath) {
List<TemplateStructure> templateFormat = new XmlReader(templatePath).getPlainStructure();
CompositeSection document= new CompositeSection();
List<Attribute> urls = source.getURIAttributes();
validateUrls(templateFormat,urls,document);
if(document.getSubSections() != null && cantNodeLink(templateFormat) > document.getSubSections().size()){
return null;
}
return document;
}
private int cantNodeLink(List<TemplateStructure> templateFormat) {
int cant=0;
for (Iterator iterator = templateFormat.iterator(); iterator.hasNext();) {
TemplateStructure templateStructure = (TemplateStructure) iterator.next();
if(templateStructure.hasLink()){
cant++;
}
}
return cant;
}
private void validateUrls(List<TemplateStructure> template,
List<Attribute> urls,CompositeSection document ) {
TemplateStructure firstItem = template.get(0);
descartarUrls(firstItem, urls);
int urlIndex = 0;
int templateIndex = 0;
boolean valid = urls.size() > 0 && validateAgainstTemplate(document, template, templateIndex,urls, urlIndex);
if (valid) {
System.out.println("Estructura VAlida");
descartarUrlsSobrantes(urls, this.lastIndexValid);
} else {
document = null;
}
}
private void descartarUrls(TemplateStructure templateItem,
List<Attribute> urls) {
boolean matching = false;
int indexFirstMatch = 0;
for (; !matching && indexFirstMatch < urls.size(); indexFirstMatch++) {
if (matching(templateItem, urls.get(indexFirstMatch))) {
matching = true;
} else {
urls.remove(indexFirstMatch);
indexFirstMatch--;
}
}
}
private boolean validateAgainstTemplate(CompositeSection document,
List<TemplateStructure> template, int templateIndex,
List<Attribute> urls, int urlIndex) {
boolean valid = false;
UrlSection urlSection = new UrlSection(urlBase);
TemplateStructure templateNode = template.get(templateIndex);
// Si nodo en el template es un item
if (templateNode.isItem()) {
document.addSection(urlSection);
//item lleno
if(templateNode.isWritten()){
urlSection.setAtt(urls.get(urlIndex),templateNode.getTitle());
if(templateNode.isChildLink()){
//Item con link hijos
templateIndex++;
valid= validateChildLinks(document,template,templateIndex, urls, urlIndex);
}else{
//Item normal
valid = validateItem(document,template,templateIndex,urls,urlIndex);
}
}else{//Item con link pendiente
urlSection.setAttNotWritten(urls.get(urlIndex),templateNode.getTitle());
valid = validateItemNotWritten(document,template,templateIndex,urls,urlIndex);
}
} else {// Seccion con link escrito
if (!templateNode.isLinkType()&& !templateNode.isItem() && templateNode.hasLink() && templateNode.isWritten()) {
document.addSection(urlSection);
urlSection.setAtt(urls.get(urlIndex),templateNode.getTitle());
valid = validateSectionWithLink(document, template,
templateIndex, urls, urlIndex);
}else
{ //Seccion con link sin completar
if(!templateNode.isLinkType()&&!templateNode.isItem() && templateNode.hasLink() && !templateNode.isWritten()){
document.addSection(urlSection);
urlSection.setAttNotWritten(urls.get(urlIndex),templateNode.getTitle());
valid = validateSectionWithLinkNotWritten(document,template,templateIndex,urls,urlIndex);
}
else {
// Seccion sin link
if (!templateNode.isLinkType()&&!templateNode.hasLink()) {
valid = validateSectionWithoutLink(document,template,templateIndex,urls,urlIndex);
}
}
}
}
return valid;
}
private boolean validateChildLinks(CompositeSection document, List<TemplateStructure> template, int templateIndex, List<Attribute> urls, int urlIndex) {
int index=0;
String sectionUrl= urls.get(urlIndex).getValue();
try{
URL url = new URL(urlBase+sectionUrl);
Source source=new Source(url);
List<Attribute> urlsChildLink = source.getURIAttributes();
descartarUrls(template.get(templateIndex), urlsChildLink);
int urlsChildLinkIndex=0;
index= validateCHildLinksAgainstTemplate( document,template, templateIndex, urlsChildLink, urlsChildLinkIndex);
if(index!=-1){
return validateAgainstTemplate(document, template, index, urls, ++urlIndex);
}
}catch (Exception e) {
return false;
}
return false;
}
private int validateCHildLinksAgainstTemplate(
CompositeSection document, List<TemplateStructure> template,
int templateIndex, List<Attribute> urlsChildLink,
int urlsChildLinkIndex) {
int index = 0;
boolean valid=false;
for (; templateIndex < template.size() && !valid;templateIndex++) {
UrlSection urlSection = new UrlSection(urlBase);
TemplateStructure templateNode = template.get(templateIndex);
if (templateNode.isLinkType()) {
if (matching(templateNode, urlsChildLink.get(urlsChildLinkIndex))) {
urlSection.setAtt(urlsChildLink.get(urlsChildLinkIndex),templateNode.getTitle());
document.addSection(urlSection);
urlsChildLinkIndex++;
}else{
return -1;
}
}else{
index=templateIndex;
valid=true;
}
}
return index;
}
private boolean validateSectionWithLinkNotWritten(
CompositeSection document, List<TemplateStructure> template,
int templateIndex, List<Attribute> urls, int urlIndex) {
boolean valid = false;
TemplateStructure templateNode = template.get(templateIndex);
Attribute att= urls.get(urlIndex);
String urlRaw= att.getValue();
if (urlRaw.contains("action=edit")) {
// Seccion VAcia
if (templateNode.isEmpty()) {
/**
* Agrego urls hasta el proximo matching...
*/
valid = validateEmptySection(document,template,templateIndex,urls,urlIndex);
} else {
// no puedo preguntar por el siguiente del template y de las
// url.. porq el template tambien es lineal. Ver de usar las dos
// estructuras mezcladas.
if (templateIndex < template.size() - 1 && urlIndex < urls.size() - 1) {
// debo validar hijos y luego avanzar. COmo la estructura
// del template es lineal. Simplemente llamo recursivamente
// avanzando en las dos estructuras
valid = validateAgainstTemplate(document,template,++templateIndex,urls,++urlIndex);
} else {
if (templateIndex < template.size() - 1) {
valid = true;
this.lastIndexValid = urlIndex;
} else {
// Recorri las urls completas. Estructura invalida
valid = false;
}
}
}
} else {
valid = false;
}
return valid;
}
private boolean validateSectionWithoutLink(CompositeSection document,
List<TemplateStructure> template, int templateIndex,
List<Attribute> urls, int urlIndex) {
boolean valid = false;
// No hay con que hacer matching por eso no se llama a dicha funcion
// Si seccion vacia recorro hasta el prox matching
if (template.get(templateIndex).isEmpty()) {
/**
* Agrego urls hast ael proximo matching...
*/
valid = validateEmptySection(document, template, templateIndex,
urls, urlIndex);
} else {// Sin link y con hijos. se llama recursivamente solo avanzando
// en el template porq como no tiene link no hay que avanzar en
// la pagina
valid = validateAgainstTemplate(document,template,++templateIndex,urls,urlIndex);
}
return valid;
}
private boolean validateItem(CompositeSection document,
List<TemplateStructure> template, int templateIndex,
List<Attribute> urls, int urlIndex) {
boolean ret;
TemplateStructure templateNode = template.get(templateIndex);
if (matching(templateNode, urls.get(urlIndex))) {
// Avanzo en ambas estructuras *1
if (templateIndex < template.size() - 1
&& urlIndex < urls.size() - 1) {
ret = validateAgainstTemplate(document, template,
++templateIndex, urls, ++urlIndex);
} else {
// Recorri el template entero. Estructura valida
if (templateIndex == template.size() - 1) {
ret = true;
this.lastIndexValid = urlIndex;
} else {
// Recorri las urls completas. Estructura invalida
ret = false;
}
}
} else {
// Corto. estructura invalida
ret = false;
}
return ret;
}
private boolean matching(TemplateStructure templateItem, Attribute url) {
// Reemplazo los espacios en blanco en los titulos del template por
// guines bajpos para pder comparar con la url en la wiki
String title = templateItem.getTitle().replaceAll(" ", "_");
// Obtengo la url del tag actual
String rawUrl = url.getValue().substring(1, url.getValue().length());
// Me quedo con el final despues de la ultima barra
String[] linkSplit = rawUrl.split(SLASH);
String link = linkSplit[linkSplit.length - 1];
/**
* A veces el link en la url tiene agregado adelante el nombre del
* proyecto o algun otro valor entonces busco las diferentes palabras
* del titulo del template en la url
*/
// String[] titlesPotentials= templateItem.getTitle().split(" ");
// String titlePotential="";
//
// for (int i = 0; i < titlesPotentials.length; i++) {
// titlePotential= titlesPotentials[i];
// if(link.contains(titlePotential)){
// return true;
// }
//
//
// }
return link.toLowerCase().contains(title.toLowerCase());
}
private boolean validateSectionWithLink(CompositeSection document,
List<TemplateStructure> template, int templateIndex,
List<Attribute> urls, int urlIndex) {
boolean valid = false;
TemplateStructure templateNode = template.get(templateIndex);
if (matching(templateNode, urls.get(urlIndex))) {
// Seccion VAcia
if (templateNode.isEmpty()) {
/**
* Agrego urls hast ael proximo matching...
*/
valid = validateEmptySection(document, template, templateIndex,
urls, urlIndex);
} else {
// no puedo preguntar por el siguiente del templat y de las
// url.. porqel template tambien es lineal. Ver d eusar las dos
// estructuras mezcladas.
if (templateIndex < template.size() - 1
&& urlIndex < urls.size() - 1) {
// debo validar hijos y luego avanzar. COmo la estructura
// del template es lineal. Simplemente llamo recursivamente
// avanzando en las dos estructuras
valid = validateAgainstTemplate(document, template,
++templateIndex, urls, ++urlIndex);
} else {
if (templateIndex < template.size() - 1) {
valid = true;
this.lastIndexValid = urlIndex;
} else {
// Recorri las urls completas. Estructura invalida
valid = false;
}
}
}
} else {
valid = false;
}
return valid;
}
private boolean validateEmptySection(CompositeSection document,
List<TemplateStructure> template, int templateIndex,
List<Attribute> urls, int urlIndex) {
boolean ret = false;
if (templateIndex < template.size() - 1) {
templateIndex = getNextItemToMatch(template, templateIndex);
TemplateStructure templateItemNext = template.get(templateIndex);
urlIndex = addUrlUntilNextMatch(document, templateItemNext, urls,
urlIndex);
ret = validateAgainstTemplate(document, template, templateIndex,
urls, urlIndex);
} else {
// Si entra aca se deben validar el resto de las urls. Ver la forma
// de solucionar porque va agregar todas las que siguen a
// continuacion
urlIndex = addRemainingUrls(document, urls, urlIndex);
ret = true;
this.lastIndexValid = urlIndex;
}
return ret;
}
/**
* Retorna el proximo elemento con el cual hacer matching. Avanza hasta que
* el nodo del template tenga un link
*
* @param templateIter
* @return
*/
private int getNextItemToMatch(List<TemplateStructure> template, int index) {
TemplateStructure ret = template.get(index);
while (!ret.hasLink()) {
if (index < template.size())
ret = template.get(++index);
}
return index;
}
private void descartarUrlsSobrantes(List<Attribute> urls, int index) {
while (index < urls.size() - 1) {
urls.remove(index);
}
}
/**
* Avanza en el iterador mientra no haga matching.
*
* @param wrapper
* @param templateItemNext
* @param urlsIter
*/
private int addUrlUntilNextMatch(CompositeSection document,
TemplateStructure templateItemNext, List<Attribute> urls,
int urlIndex) {
// Mientras haya urls y no haga matching sigue avanzando ene el iterador
while (urlIndex < urls.size()
&& !matching(templateItemNext, urls.get(urlIndex))) {
UrlSection child = new UrlSection(urlBase);
child.setAtt(urls.get(urlIndex),templateItemNext.getTitle());
document.addSection(child);
urlIndex++;
}
return urlIndex;
}
/**
* Avanza hasta el final del iterador
*
* @param wrapper
* @param urlsIter
*/
private int addRemainingUrls(CompositeSection document, List<Attribute> urls,
int urlIndex) {
while (urlIndex < urls.size()) {
UrlSection child = new UrlSection(urlBase);
String title= getTitle(urls.get(urlIndex));
child.setAtt(urls.get(urlIndex),title);
document.addSection(child);
urlIndex++;
}
return urlIndex;
}
private String getTitle(Attribute attribute) {
String rawUrl = attribute.getValue().substring(1, attribute.getValue().length());
// Me quedo con el final despues de la ultima barra
String[] linkSplit = rawUrl.split(SLASH);
String link = linkSplit[linkSplit.length - 1];
String title =link.replaceAll("_"," ");
return title;
}
/**
* @param args
* @throws IOException
*/
// public static void main(String[] args) throws IOException {
//
// double t1, t2;
// t1 = System.currentTimeMillis();
//
// String path= "https://wiki.sei.cmu.edu/sad/index.php/The_Java_Pet_Store_SAD";
//
// SadParser parser= SadParserFactory.getParser(SadParserFactory.WIKI);
//
// CompositeSection doc= (CompositeSection) parser.getSad(path);
//
//
// t2= System.currentTimeMillis();
//
// System.out.println("Tiempo de ejecucion: "+(t2-t1)/1000.0);
//
// }
private boolean validateItemNotWritten(CompositeSection document,
List<TemplateStructure> template, int templateIndex,
List<Attribute> urls, int urlIndex) {
boolean ret;
Attribute att= urls.get(urlIndex);
String urlRaw= att.getValue();
if (urlRaw.contains("action=edit")) {
// Avanzo en ambas estructuras *1
if (templateIndex < template.size() - 1
&& urlIndex < urls.size() - 1) {
ret = validateAgainstTemplate(document, template,
++templateIndex, urls, ++urlIndex);
} else {
// Recorri el template entero. Estructura valida
if (templateIndex == template.size() - 1) {
ret = true;
this.lastIndexValid = urlIndex;
} else {
// Recorri las urls completas. Estructura invalida
ret = false;
}
}
} else {
// Corto. estructura invalida
ret = false;
}
return ret;
}
}