package rra.parser;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.collections.CollectionUtils;
import rra.model.Combat;
import rra.model.DPSStats;
import rra.model.RRAData;
import rra.model.RRAException;
import rra.model.RRAPredicate;
import rra.model.RRAUtils;
public class RRAParser {
public static final String EventBeginCast="1";
public static final String EventInterrupt="2";
public static final String EventDamage="3";
public static final String EventDoTDamage="4";
public static final String EventHeal="5";
public static final String EventAbilityGain="6";
public static final String EventAbilityFade="7";
public static final String EventAuraAffliction="8";
public static final String EventAuraDisspiation="9";
public static final String EventMiss="10";
public static final String EventSlain="11";
public static final String EventDeath="12";
public static final String EventDamageTake="14";
public static final String EventDodge="15";
public static final String EventParry="16";
public static final String EventResist="19";
public static final String EventCritDamage="23";
public static final String EventImmune="26";
public static final String EventResourceGain="27";
public static final String EventCritHeal="28";
private RRAData data=null;
private Calendar c=null;
private SimpleDateFormat sdf=null;
private Pattern p1=null;
private Pattern p2=null;
private Pattern p3=null;
private Pattern p4=null;
private Pattern p5=null;
private Pattern p6=null;
private boolean combatSpecialFlag=false;
public RRAParser() {
this.data=new RRAData();
this.c=Calendar.getInstance();
this.sdf=new SimpleDateFormat("HH:mm:ss");
this.p1=Pattern.compile("[0-9]*:[0-9]*:[0-9]*");
this.p2=Pattern.compile("\\([ ].*[ ]\\)");
this.p3=Pattern.compile("[0-9]+");
this.p4=Pattern.compile("[ ][^0-9\\)]+");
this.p5=Pattern.compile("\\([0-9]+[ ].*[^0-9\\)]+\\)");
this.p6=Pattern.compile("[0-9]+[ ][^0-9\\)]+");
}
public List<Combat> getCombatList() {
return this.data.getCombatList();
}
public Combat getCombat(String name) {
return (Combat)CollectionUtils.find(this.data.getCombatList(), new RRAPredicate(new Combat(0,name,null)));
}
public boolean parse(String s,boolean disposeSmall,int disposeActions,boolean pruneHealing) {
if(s.contains("Combat Begin")) this.combatSpecialFlag=true;
if(s.contains("Combat End")) this.combatSpecialFlag=false;
Combat com1=this.data.getLastCombat();
long tstamp=0;
Date comStart=null;
Matcher m1=p1.matcher(s);
if(m1.find()) {
String ts1=m1.group();
if(ts1.length()>0) {
try {
comStart=sdf.parse(ts1);
c.setTime(comStart);
int hour=c.get(Calendar.HOUR_OF_DAY);
int minute=c.get(Calendar.MINUTE);
int second=c.get(Calendar.SECOND);
tstamp=hour*3600+minute*60+second;
} catch (ParseException e) {
e.printStackTrace();
}
}
}
if(tstamp==0) {
//System.out.println("Parser error: timestamp cannot be determined for ("+s+")");
return false;
}
Matcher m2=p2.matcher(s);
if(!m2.find()) {
//System.out.println("Parser error: no main brackets for ("+s+")");
return false;
}
String s1=m2.group();
if(s1.length()<2) {
//System.out.println("Parser error: main content too short ("+s1+")");
return false;
}
String s2=s1.substring(1, s1.length()-2);
String[] values=s2.split(",");
for(int i1=0;i1<values.length;i1++)
values[i1]=values[i1].trim();
List<RRAParserMitigation> mitigations=new ArrayList<RRAParserMitigation>();
Matcher m5=p5.matcher(s);
if(m5.find()) {
String s3=m5.group();
Matcher m6=p6.matcher(s3);
while(m6.find()) {
String s4=m6.group();
Matcher m3=p3.matcher(s4);
Matcher m4=p4.matcher(s4);
if(m3.find() && m4.find()) {
RRAParserMitigation mit=new RRAParserMitigation();
try {
mit.setDamageMitigated(Long.parseLong(m3.group()));
} catch (NumberFormatException e) {
e.printStackTrace();
}
mit.setMitigation(m4.group().trim());
mitigations.add(mit);
}
}
}
String damageType="Physical";
if(s.contains("Death")) damageType="Death";
else if(s.contains("Air")) damageType="Air";
else if(s.contains("Water")) damageType="Water";
else if(s.contains("Fire")) damageType="Air";
else if(s.contains("Life")) damageType="Life";
else if(s.contains("Earth")) damageType="Earth";
// Types
/*
* 1 - Begin cast
* 2 - Interrupt
* 3 - Damage
* 4 - DoT damage
* 5 - Heal
* 6 - Ability gain
* 7 - Ability fade
* 8 - Aura affliction
* 9 - Aura dissipation
* 10 - Miss
* 11 - Slain (death)
* 12 - Death (general)
* 14 - Damage take (unknown causer)
* 15 - Dodge
* 16 - Parry
* 19 - Resist
* 23 - Critical damage
* 26 - Immune
* 27 - Resource gain
* 28 - Critical heal
*/
// If we have damage type and last combat doesn't exist or is done, we need new combat
if(values[0].equals(RRAParser.EventDamage) ||
values[0].equals(RRAParser.EventDoTDamage) ||
values[0].equals(RRAParser.EventCritDamage) ||
(this.combatSpecialFlag && values[0].equals(RRAParser.EventHeal)) ||
(this.combatSpecialFlag && values[0].equals(RRAParser.EventCritHeal)) ||
values[0].equals(RRAParser.EventDamageTake)) {
if(com1==null || !com1.isActive()) {
com1=data.addNewCombat();
com1.startCombat(comStart,tstamp);
}
}
if(com1==null) return false;
if(com1.isActive()) {
if(com1.getName().contains("Trash")) {
if(RRAUtils.checkIfParticipantIsKnownEnemy(values[5])!=null)
com1.setSpecialName(RRAUtils.checkIfParticipantIsKnownEnemy(values[5]));
}
if(com1.getName().contains("Trash")) {
if(RRAUtils.checkIfParticipantIsKnownEnemy(values[6])!=null)
com1.setSpecialName(RRAUtils.checkIfParticipantIsKnownEnemy(values[6]));
}
com1.setCombatDuration(tstamp);
}
if(values[0].equals(RRAParser.EventDamage) || values[0].equals(RRAParser.EventDoTDamage)) {
long damage=Long.parseLong(values[7]);
try {
com1.addDamageEvent(tstamp, values[5], values[6], damage, values[9], DPSStats.OutcomeHit, damageType);
for(Iterator<RRAParserMitigation> m=mitigations.iterator();m.hasNext();) {
RRAParserMitigation mit=m.next();
if(mit.getMitigation().equalsIgnoreCase("blocked"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeBlock, damageType);
if(mit.getMitigation().equalsIgnoreCase("absorbed"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeAbsorbed, damageType);
if(mit.getMitigation().equalsIgnoreCase("intercepted"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeIntercepted, damageType);
}
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventCritDamage)) {
long damage=Long.parseLong(values[7]);
try {
com1.addDamageEvent(tstamp, values[5], values[6], damage, values[9], DPSStats.OutcomeCrit, damageType);
for(Iterator<RRAParserMitigation> m=mitigations.iterator();m.hasNext();) {
RRAParserMitigation mit=m.next();
if(mit.getMitigation().equalsIgnoreCase("blocked"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeBlock, damageType);
if(mit.getMitigation().equalsIgnoreCase("absorbed"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeAbsorbed, damageType);
if(mit.getMitigation().equalsIgnoreCase("intercepted"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeIntercepted, damageType);
}
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventMiss)) {
try {
com1.addDamageEvent(tstamp, values[5], values[6], 0, values[9], DPSStats.OutcomeMiss, damageType);
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventDodge)) {
try {
com1.addDamageEvent(tstamp, values[5], values[6], 0, values[9], DPSStats.OutcomeDodge, damageType);
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventParry)) {
try {
com1.addDamageEvent(tstamp, values[5], values[6], 0, values[9], DPSStats.OutcomeParry, damageType);
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventResist)) {
try {
com1.addDamageEvent(tstamp, values[5], values[6], 0, values[9], DPSStats.OutcomeResist, damageType);
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventHeal) || values[0].equals(RRAParser.EventCritHeal)) {
long heal=Long.parseLong(values[7]);
long overheal=0;
try {
for(Iterator<RRAParserMitigation> m=mitigations.iterator();m.hasNext();) {
RRAParserMitigation mit=m.next();
if(mit.getMitigation().equalsIgnoreCase("overheal")) overheal=mit.getDamageMitigated();
}
com1.addHealingEvent(tstamp, values[5], values[6], heal, values[9], overheal, (values[0].equals(RRAParser.EventCritHeal)));
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventSlain)) {
try {
com1.addDeath(tstamp, values[6], values[5]);
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventDeath)) {
try {
com1.addDeath(tstamp, values[5], "Unknown");
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventInterrupt)) {
try {
com1.addInterrupt(tstamp, values[5], values[9]);
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(values[0].equals(RRAParser.EventDamageTake)) {
long damage=Long.parseLong(values[7]);
try {
com1.addDamageTakenEvent(tstamp, values[5], values[6], damage, values[9], DPSStats.OutcomeHit, damageType);
for(Iterator<RRAParserMitigation> m=mitigations.iterator();m.hasNext();) {
RRAParserMitigation mit=m.next();
if(mit.getMitigation().equalsIgnoreCase("blocked"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeBlock, damageType);
if(mit.getMitigation().equalsIgnoreCase("absorbed"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeAbsorbed, damageType);
if(mit.getMitigation().equalsIgnoreCase("intercepted"))
com1.addDamageEvent(tstamp, values[5], values[6], mit.getDamageMitigated(), values[9], DPSStats.OutcomeIntercepted, damageType);
}
} catch (RRAException e) {
//e.printStackTrace();
}
}
if(com1.tryToCloseCombat(tstamp, pruneHealing)) {
if(disposeSmall && disposeActions>0 && com1.getCombatActions()<=disposeActions) {
this.data.getCombatList().remove(com1);
return false;
} else return true;
} else return false;
}
public RRAData getData() {
return this.data;
}
}