package com.actelion.research.chem.phesa;

import com.actelion.research.calc.Matrix;
import com.actelion.research.chem.Coordinates;
import com.actelion.research.chem.PeriodicTable;
import com.actelion.research.chem.StereoMolecule;
import com.actelion.research.chem.conf.Conformer;
import com.actelion.research.util.EncoderFloatingPointNumbers;

public class VolumeGaussian extends Gaussian3D {
	public static final int INCLUSION = 1;
	public static final int EXCLUSION = -1;
	private Coordinates shiftVector;
	private Coordinates referenceVector;
	private int role; //-1 for exclusion, +1 for inclusion
	
	public VolumeGaussian(int atomId,int atomicNo,Coordinates center, Coordinates shiftVector, int role){
		super(atomId,atomicNo,center.addC(shiftVector),1.0);
		this.shiftVector = shiftVector;
		this.referenceVector = center;
		this.role = role;
	}
	
	public VolumeGaussian(VolumeGaussian original){
		super(original.atomId,original.atomicNo,original.center, original.weight);
		this.shiftVector = new Coordinates(original.shiftVector);
		this.referenceVector = new Coordinates(original.referenceVector);
		this.role = original.role;
	}
	
	private VolumeGaussian(String encodedGaussian, StereoMolecule mol) {
		decode(encodedGaussian, mol);
	}
	
	public static VolumeGaussian fromString(String encodedGaussian, StereoMolecule mol) {
		return new VolumeGaussian(encodedGaussian, mol);
	}


	@Override
	public String encode() { //encodes all information of a atomicGaussian using the Base64 encoder
		double[] shift = new double[] {shiftVector.x,shiftVector.y, shiftVector.z};
		StringBuilder molVolString = new StringBuilder();
		molVolString.append(Integer.toString(atomicNo));
		molVolString.append(" ");
		molVolString.append(Integer.toString(atomId));
		molVolString.append(" ");
		molVolString.append(EncoderFloatingPointNumbers.encode(shift,13));
		molVolString.append(" ");
		molVolString.append(Integer.toString(role));
		return molVolString.toString();
	}
	
	public void decode(String string64, StereoMolecule mol)  {
		String[] strings = string64.split(" ");
		atomicNo = Integer.decode(strings[0]);
		atomId = Integer.decode(strings[1]);
		double [] shift = EncoderFloatingPointNumbers.decode(strings[2]);
		role = Integer.decode(strings[3]);
		alpha = calculateWidth(); //the width of the Gaussian depends on the atomic radius of the atom
		volume = calculateVolume();
		coeff = calculateHeight();
		referenceVector = new Coordinates(mol.getAtomX(atomId), mol.getAtomY(atomId), mol.getAtomZ(atomId));
		shiftVector = new Coordinates(shift[0],shift[1],shift[2]);
		center = referenceVector.addC(shiftVector);
		weight = 1.0;
		
	}

	@Override
	public double calculateHeight() {
		return MolecularVolume.p;
	}

	@Override
	public double calculateWidth() {
		double vdwR = PeriodicTable.getElement(atomicNo).getVDWRadius();
		return MolecularVolume.alpha_pref/(vdwR*vdwR);
	}
	
	public void updateCoordinates(StereoMolecule mol) {
		referenceVector = new Coordinates(mol.getAtomCoordinates(atomId));
		center = referenceVector.addC(shiftVector);
	}
	
	public void updateCoordinates(Conformer conf) {
		referenceVector = new Coordinates(conf.getCoordinates(atomId));
		center = referenceVector.addC(shiftVector);
	}
	
	public void setShiftVector(Coordinates shift) {
		this.shiftVector = shift;
	}
	
	public Coordinates getShiftVector() {
		return this.shiftVector;
	}
	
	public void addShift(Coordinates shift) {
		shiftVector.add(shift);
		center = referenceVector.addC(shiftVector);
	}
	
	public void translateRef(Coordinates trans) {
		referenceVector.add(trans);
		center = referenceVector.addC(shiftVector);
	}
	
	public void rotateShift(Matrix rotMat) {
		//PheSAAlignment.rotateCoords(shiftVector, rotMat.getArray());
		shiftVector.rotate(rotMat.getArray());
		center = referenceVector.addC(shiftVector);
	}
	
	public Coordinates getReferenceVector() {
		return this.referenceVector;
	}
	
	public void setReferenceVector(Coordinates referenceVector) {
		this.referenceVector = referenceVector;
	}
	
	public int getRole() {
		return role;
	}
	
	
	

	
	

}
