package somiba.domain;

import java.util.Vector;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

class SeasonCompositeKey implements java.io.Serializable {
	private static final long serialVersionUID = 1L;
	private String name;
    private String year;
    private String team;
	public String getName() { return name; }
	public void setName(String name) { this.name = name; }
	public String getYear() { return year; }
	public void setYear(String year) { this.year = year; }
	public String getTeam() { return team; }
	public void setTeam(String team) { this.team = team; }
}

@IdClass(SeasonCompositeKey.class)
@Entity
@Table(name="season")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Season {
	@Id @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="name", referencedColumnName = "name")

	private String name;
	private String year;
	private String team;
	private int gp, gs, min, fgm, fga, tpm, tpa, ftm, fta, pts;
	private int off, def, ast, pf, dq, stl, to, blk;
	
	public Season(String name, String year, String team) {
		this.name = name;
		this.year = year;
		this.team = team;
	}

	public Season(String year) {
		this("", year, "");
	}
	
	public Season() {}

	double compareValue;
	int formatValue;

	public boolean parse(String line) {
		name = line.substring(0, 9).trim().toUpperCase().replace(' ', '_');
		String[] vals = line.substring(10).trim().split("\\s+"); 
		gp = getInt(vals[0]);
		gs = getInt(vals[1]);
		if (gs > 99)
			return false;
		min = getInt(vals[2]);
		fgm = getInt(vals[3]);
		fga = getInt(vals[4]);
		tpm = getInt(vals[6]);
		tpa = getInt(vals[7]);
		ftm = getInt(vals[9]);
		fta = getInt(vals[10]);
		pts = getInt(vals[12]);
		return true;
	}

	public void secondParse(String team, String line) {
		this.team = team;
		String[] vals = line.substring(9).trim().split("\\s+"); 
		off = getInt(vals[0]);
		def = getInt(vals[1]);
		ast = getInt(vals[3]);
		pf = getInt(vals[4]);
		dq = getInt(vals[5]);
		stl = getInt(vals[6]);
		to = getInt(vals[7]);
		blk = getInt(vals[8]);
	}

	int getInt(String chars) {
		return Integer.valueOf(chars.trim()).intValue();
	}

	public void increment(Season season) {
		gp += season.getGp();
		gs += season.getGs();
		min += season.getMin();
		fgm += season.getFgm();
		fga += season.getFga();
		tpm += season.getTpm();
		tpa += season.getTpa();
		ftm += season.getFtm();
		fta += season.getFta();
		pts += season.getPts();
		off += season.getOff();
		def += season.getDef();
		ast += season.getAst();
		pf += season.getPf();
		dq += season.getDq();
		stl += season.getStl();
		to += season.getTo();
		blk += season.getBlk();
	}

	public String toString() {
		String fgpct = processPct(fgm, fga);
		String ftpct = processPct(ftm, fta);
		String tppct = processPct(tpm, tpa);
		String avg = processPct(pts, gp * 100);
		String rpg = processPct((off + def), gp * 100);
		String apg = processPct(ast, gp * 100);
		return year + " " + team + process(gp, 4) + process(gs, 4)
				+ process(min, 6) + process(fgm, 6) + process(fga, 6) + " "
				+ fgpct + process(tpm, 5) + process(tpa, 5) + " " + tppct
				+ process(ftm, 5) + process(fta, 5) + " " + ftpct
				+ process(blk, 5) + process(stl, 5) + process(to, 5)
				+ process(pf, 5) + process(off, 5) + process((off + def), 6)
				+ " " + rpg + process(ast, 6) + " " + apg + process(pts, 6)
				+ " " + avg;
	}

	public String customFill(double divisor) {
		String fgpct = processPct(fgm, fga);
		String ftpct = processPct(ftm, fta);
		String tppct = processPct(tpm, tpa);
		name = process(name, 9);
		year = process(year, 2);
		team = process(team, 9);
		String beginning = (name + " " + year + " " + team + process(gp, 4) + process(gs, 4));
		String ending = null;
		if (divisor > 0.) {
			ending = processAvg(min / divisor, 6)
			+ processAvg(fgm / divisor, 6)
			+ processAvg(fga / divisor, 6) + " " + fgpct
			+ processAvg(tpm / divisor, 5)
			+ processAvg(tpa / divisor, 5) + " " + tppct
			+ processAvg(ftm / divisor, 5)
			+ processAvg(fta / divisor, 5) + " " + ftpct
			+ processAvg(stl / divisor, 5)
			+ processAvg(blk / divisor, 5)
			+ processAvg(to / divisor, 5)
			+ processAvg(pf / divisor, 5)
			+ processAvg(off / divisor, 5)
			+ processAvg((off + def) / divisor, 6)
			+ processAvg(ast / divisor, 6)
			+ processAvg(pts / divisor, 6);
		}
		else {
			ending = process(min, 6) + process(fgm, 6) + process(fga, 6) + " "
			+ fgpct + process(tpm, 5) + process(tpa, 5) + " " + tppct
			+ process(ftm, 5) + process(fta, 5) + " " + ftpct
			+ process(stl, 5) + process(blk, 5) + process(to, 5)
			+ process(pf, 5) + process(off, 5) + process((off + def), 6)
			+ process(ast, 6) + process(pts, 6);
		}
		return beginning + ending;
	}
	   
	public void fill(Vector<String> averages, Vector<String> raw) {
		String fgpct = processPct(fgm, fga);
		String ftpct = processPct(ftm, fta);
		String tppct = processPct(tpm, tpa);
		year = process(year, 2);
		team = process(team, 9);
		averages.add(year + " " + team + process(gp, 4) + process(gs, 4)
				+ processAvg((double) min / gp, 6)
				+ processAvg((double) fgm / gp, 6)
				+ processAvg((double) fga / gp, 6) + " " + fgpct
				+ processAvg((double) tpm / gp, 5)
				+ processAvg((double) tpa / gp, 5) + " " + tppct
				+ processAvg((double) ftm / gp, 5)
				+ processAvg((double) fta / gp, 5) + " " + ftpct
				+ processAvg((double) stl / gp, 5)
				+ processAvg((double) blk / gp, 5)
				+ processAvg((double) to / gp, 5)
				+ processAvg((double) pf / gp, 5)
				+ processAvg((double) off / gp, 5)
				+ processAvg((double) (off + def) / gp, 6)
				+ processAvg((double) ast / gp, 6)
				+ processAvg((double) pts / gp, 6));
		raw.add(year + " " + team + process(gp, 4) + process(gs, 4)
				+ process(min, 6) + process(fgm, 6) + process(fga, 6) + " "
				+ fgpct + process(tpm, 5) + process(tpa, 5) + " " + tppct
				+ process(ftm, 5) + process(fta, 5) + " " + ftpct
				+ process(stl, 5) + process(blk, 5) + process(to, 5)
				+ process(pf, 5) + process(off, 5) + process((off + def), 6)
				+ process(ast, 6) + process(pts, 6));
	}

	String processPct(int val1, int val2) {
		if (val1 == val2 && val1 > 0)
			return "100.";
		StringBuffer buf = new StringBuffer(5);
		StringBuffer first = new StringBuffer(String
				.valueOf((int) (100. * val1 / val2)));
		for (int i = 0; i < 2 - first.length(); i++)
			buf.append(" ");
		buf.append(first + ".");
		int second = (int) (1000. * val1 / val2) % 10;
		return buf.append(String.valueOf(second)).toString();
	}

	String process(int val, int length) {
		StringBuffer buf = new StringBuffer(length);
		StringBuffer buf2 = new StringBuffer(String.valueOf(val));
		for (int i = 0; i < length - buf2.length(); i++)
			buf.append(" ");
		return buf.append(buf2).toString();
	}

	String process(String val, int length) {
		StringBuilder buf = new StringBuilder(val);
		for (int i = 0; i < length - val.length(); i++)
			buf.append(" ");
		return buf.toString();
	}

	String processAvg(double val, int length) {
		StringBuffer buf = new StringBuffer(length);
		String full = String.valueOf(val + 0.05);
		StringBuffer buf2 = new StringBuffer(full.substring(0, full
				.indexOf('.') + 2));
		for (int i = 0; i < length - buf2.length(); i++)
			buf.append(" ");
		return buf.append(buf2).toString();
	}

	public boolean processStat(String time, String stat, Player player) {
		if (team.equals("Totals") && time.equals("single"))
			return false;
		if (gp == 0.)
			return false;
		if (player == null)
			return false;
		boolean single;
		if (time.equals("single"))
			single = true;
		else
			single = false;
		if (stat.equals("ppg")) {
			if (pts < (single ? 1400 : 10000) && gp < (single ? 70 : 400))
				return false;
			setCompareValue(pts / (double) gp, 2);
		}
		if (stat.equals("pts"))
			setCompareValue((double) pts, 0);
		if (stat.equals("rpg")) {
			if ((off + def) < (single ? 800 : 5000) && gp < (single ? 70 : 400))
				return false;
			setCompareValue((off + def) / (double) gp, 2);
		}
		if (stat.equals("reb"))
			setCompareValue((double) (off + def), 0);
		if (stat.equals("apg")) {
			if (ast < (single ? 400 : 2500) && gp < (single ? 70 : 400))
				return false;
			setCompareValue(ast / (double) gp, 2);
		}
		if (stat.equals("ast"))
			setCompareValue((double) ast, 0);
		if (stat.equals("stl"))
			setCompareValue((double) stl, 0);
		if (stat.equals("blk"))
			setCompareValue((double) blk, 0);
		if (stat.equals("to"))
			setCompareValue((double) to, 0);
		if (stat.equals("fgp")) {
			if (fgm < (single ? 300 : 2000))
				return false;
			setCompareValue(fgm / (double) fga * 100., 1);
		}
		if (stat.equals("fga"))
			setCompareValue((double) fga, 0);
		if (stat.equals("fgm"))
			setCompareValue((double) fgm, 0);
		if (stat.equals("ftp")) {
			if (ftm < (single ? 125 : 1200))
				return false;
			setCompareValue(ftm / (double) fta * 100., 1);
		}
		if (stat.equals("fta"))
			setCompareValue((double) fta, 0);
		if (stat.equals("ftm"))
			setCompareValue((double) ftm, 0);
		if (stat.equals("tpp")) {
			if (tpm < (single ? 55 : 250))
				return false;
			setCompareValue(tpm / (double) tpa * 100., 1);
		}
		if (stat.equals("tpa"))
			setCompareValue((double) tpa, 0);
		if (stat.equals("tpm")) {
			setCompareValue((double) tpm, 0);
		}
		if (stat.equals("tsp")) {
			if (min < (single ? 1000 : 10000))
				return false;
			setCompareValue(pts / (fga + 0.44 * fta) * 50., 1);
		}
		return true;
	}

	public void setCompareValue(double _compareValue, int _formatValue) {
		compareValue = _compareValue;
		formatValue = _formatValue;
	}

	@Transient
	public double getCompareValue() {
		return compareValue;
	}

	@Transient
	public int getFormatValue() {
		return formatValue;
	}

	@Column(length = 9, nullable = false)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Id
	@Column(length = 4, nullable = false)
	public String getYear() {
		return year;
	}
	public void setYear(String year) {
		this.year = year;
	}
	@Id
	@Column(length = 9, nullable = false)
	public String getTeam() {
		return team;
	}
	public void setTeam(String team) {
		this.team = team;
	}
	@Column(precision = 5, nullable = false)  
	public int getGp() {
		return gp;
	}
	public void setGp(int gp) {
		this.gp = gp;
	}
	@Column(precision = 5, nullable = false)  
	public int getGs() {
		return gs;
	}
	public void setGs(int gs) {
		this.gs = gs;
	}
	@Column(name = "mp", precision = 8, nullable = false)  
	public int getMin() {
		return min;
	}
	public void setMin(int min) {
		this.min = min;
	}
	@Column(precision = 5, nullable = false)  
	public int getFgm() {
		return fgm;
	}
	public void setFgm(int fgm) {
		this.fgm = fgm;
	}
	@Column(precision = 5, nullable = false)  
	public int getFga() {
		return fga;
	}
	public void setFga(int fga) {
		this.fga = fga;
	}
	@Column(precision = 5, nullable = false)  
	public int getTpm() {
		return tpm;
	}
	public void setTpm(int tpm) {
		this.tpm = tpm;
	}
	@Column(precision = 5, nullable = false)  
	public int getTpa() {
		return tpa;
	}
	public void setTpa(int tpa) {
		this.tpa = tpa;
	}
	@Column(precision = 5, nullable = false)  
	public int getFtm() {
		return ftm;
	}
	public void setFtm(int ftm) {
		this.ftm = ftm;
	}
	@Column(precision = 5, nullable = false)  
	public int getFta() {
		return fta;
	}
	public void setFta(int fta) {
		this.fta = fta;
	}
	@Column(precision = 8, nullable = false)  
	public int getPts() {
		return pts;
	}
	public void setPts(int pts) {
		this.pts = pts;
	}
	@Column(precision = 5, nullable = false)  
	public int getOff() {
		return off;
	}
	public void setOff(int off) {
		this.off = off;
	}
	@Column(precision = 5, nullable = false)  
	public int getDef() {
		return def;
	}
	public void setDef(int def) {
		this.def = def;
	}
	@Column(precision = 5, nullable = false)  
	public int getAst() {
		return ast;
	}
	public void setAst(int ast) {
		this.ast = ast;
	}
	@Column(precision = 5, nullable = false)  
	public int getPf() {
		return pf;
	}
	public void setPf(int pf) {
		this.pf = pf;
	}
	@Column(precision = 5, nullable = false)  
	public int getDq() {
		return dq;
	}
	public void setDq(int dq) {
		this.dq = dq;
	}
	@Column(precision = 5, nullable = false)  
	public int getStl() {
		return stl;
	}
	public void setStl(int stl) {
		this.stl = stl;
	}
	@Column(name = "trn", precision = 5, nullable = false)  
	public int getTo() {
		return to;
	}
	public void setTo(int to) {
		this.to = to;
	}
	@Column(precision = 5, nullable = false)  
	public int getBlk() {
		return blk;
	}
	public void setBlk(int blk) {
		this.blk = blk;
	}

}
