Source: core/kekule.valences.js

/**
 * @fileoverview
 * This file helps to determine the valence of a neutral, anion(-) or cation(+) atom. 
 * @author Partridge Jiang
 */

/**
 * A class to help to determinate the valence of atom, especially with charge.
 * @class
 */
Kekule.ValenceUtils = {
	/**
	 * Returns the implicit MDL valence for element with charge and known (explicit) valence.
	 * e.g. C+ valence is 3 while C- valence is also 3.
	 * The code is copy from mdlvalence.h of OpenBabel.
	 * See https://github.com/openbabel/openbabel/blob/master/src/formats/mdlvalence.h
	 * @param {Int} atomicNumber
	 * @param {Int} charge
	 * @param {Int} explicitValence
	 * @returns {Int}
	 */
	getImplicitMdlValence: function(atomicNumber, charge, explicitValence)
	{
		var q = charge;
		var val = explicitValence;
		
		switch (atomicNumber) {
		  case 1: // H
		  case 3: // Li
		  case 11: // Na
		  case 19: // K
		  case 37: // Rb
		  case 55: // Cs
		  case 87: // Fr
		    if (q == 0 && val <= 1)
		      return 1;
		    break;
		
		  case 4: // Be
		  case 12: // Mg
		  case 20: // Ca
		  case 38: // Sr
		  case 56: // Ba
		  case 88: // Ra
		    switch (q) {
		    case 0: if (val <= 2) return 2; break;
		    case 1: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 5: // B
		    switch (q) {
		    case -4: if (val <= 1) return 1; break;
		    case -3: if (val <= 2) return 2; break;
		    case -2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case -1: if (val <= 4) return 4; break;
		    case 0: if (val <= 3) return 3; break;
		    case 1: if (val <= 2) return 2; break;
		    case 2: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 6: // C
		    switch (q) {
		    case -3: if (val <= 1) return 1; break;
		    case -2: if (val <= 2) return 2; break;
		    case -1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 0: if (val <= 4) return 4; break;
		    case 1: if (val <= 3) return 3; break;
		    case 2: if (val <= 2) return 2; break;
		    case 3: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 7: // N
		    switch (q) {
		    case -2: if (val <= 1) return 1; break;
		    case -1: if (val <= 2) return 2; break;
		    case 0: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 1: if (val <= 4) return 4; break;
		    case 2: if (val <= 3) return 3; break;
		    case 3: if (val <= 2) return 2; break;
		    case 4: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 8: // O
		    switch (q) {
		    case -1: if (val <= 1) return 1; break;
		    case 0: if (val <= 2) return 2; break;
		    case 1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 2: if (val <= 4) return 4; break;
		    case 3: if (val <= 3) return 3; break;
		    case 4: if (val <= 2) return 2; break;
		    case 5: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 9: // F
		    switch (q) {
		    case 0: if (val <= 1) return 1; break;
		    case 1: if (val <= 2) return 2; break;
		    case 2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 3: if (val <= 4) return 4; break;
		    case 4: if (val <= 3) return 3; break;
		    case 5: if (val <= 2) return 2; break;
		    case 6: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 13: // Al
		    switch (q) {
		    case -4: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -3: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case -2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case -1: if (val <= 4) return 4; break;
		    case 0: if (val <= 3) return 3; break;
		    case 1: if (val <= 2) return 2; break;
		    case 2: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 14: // Si
		    switch (q) {
		    case -3: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -2: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case -1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 0: if (val <= 4) return 4; break;
		    case 1: if (val <= 3) return 3; break;
		    case 2: if (val <= 2) return 2; break;
		    case 3: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 15: // P
		    switch (q) {
		    case -2: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -1: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 0: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 1: if (val <= 4) return 4; break;
		    case 2: if (val <= 3) return 3; break;
		    case 3: if (val <= 2) return 2; break;
		    case 4: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 16: // S
		    switch (q) {
		    case -1: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case 0: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 2: if (val <= 4) return 4; break;
		    case 3: if (val <= 3) return 3; break;
		    case 4: if (val <= 2) return 2; break;
		    case 5: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 17: // Cl
		    switch (q) {
		    case 0: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case 1: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 3: if (val <= 4) return 4; break;
		    case 4: if (val <= 3) return 3; break;
		    case 5: if (val <= 2) return 2; break;
		    case 6: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 31: // Ga
		    switch (q) {
		    case -4: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -3: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case -2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case -1: if (val <= 4) return 4; break;
		    case 0: if (val <= 3) return 3; break;
		    case 2: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 32: // Ge
		    switch (q) {
		    case -3: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -2: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case -1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 0: if (val <= 4) return 4; break;
		    case 1: if (val <= 3) return 3; break;
		    case 3: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 33: // As
		    switch (q) {
		    case -2: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -1: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 0: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 1: if (val <= 4) return 4; break;
		    case 2: if (val <= 3) return 3; break;
		    case 4: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 34: // Se
		    switch (q) {
		    case -1: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case 0: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 2: if (val <= 4) return 4; break;
		    case 3: if (val <= 3) return 3; break;
		    case 5: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 35: // Br
		    switch (q) {
		    case 0: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case 1: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 3: if (val <= 4) return 4; break;
		    case 4: if (val <= 3) return 3; break;
		    case 6: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 49: // In
		    switch (q) {
		    case -4: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -3: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case -2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case -1: if (val <= 2) return 2;
		              if (val <= 4) return 4; break;
		    case 0: if (val <= 3) return 3; break;
		    case 2: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 50: // Sn
		  case 82: // Pb
		    switch (q) {
		    case -3: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -2: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case -1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 0: if (val <= 2) return 2;
		              if (val <= 4) return 4; break;
		    case 1: if (val <= 3) return 3; break;
		    case 3: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 51: // Sb
		  case 83: // Bi
		    switch (q) {
		    case -2: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -1: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 0: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 1: if (val <= 2) return 2;
		              if (val <= 4) return 4; break;
		    case 2: if (val <= 3) return 3; break;
		    case 4: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 52: // Te
		  case 84: // Po
		    switch (q) {
		    case -1: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case 0: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 1: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 2: if (val <= 2) return 2;
		              if (val <= 4) return 4; break;
		    case 3: if (val <= 3) return 3; break;
		    case 5: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 53: // I
		  case 85: // At
		    switch (q) {
		    case 0: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case 1: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case 2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case 3: if (val <= 2) return 2;
		              if (val <= 4) return 4; break;
		    case 4: if (val <= 3) return 3; break;
		    case 6: if (val <= 1) return 1; break;
		    }
		    break;
		
		  case 81: // Tl
		    switch (q) {
		    case -4: if (val <= 1) return 1;
		              if (val <= 3) return 3;
		              if (val <= 5) return 5;
		              if (val <= 7) return 7; break;
		    case -3: if (val <= 2) return 2;
		              if (val <= 4) return 4;
		              if (val <= 6) return 6; break;
		    case -2: if (val <= 3) return 3;
		              if (val <= 5) return 5; break;
		    case -1: if (val <= 2) return 2;
		              if (val <= 4) return 4; break;
		    case 0: if (val <= 1) return 1;
		              if (val <= 3) return 3; break;
		    }
		    break;
		
		  }
		  return val;
	},
	
	/**
	 * Returns the implicit HYD valence for element with charge and known (explicit) valence.
	 * The code is copy from mdlvalence.h of OpenBabel.
	 * See https://github.com/openbabel/openbabel/blob/master/src/formats/mdlvalence.h
	 * @param {Int} atomicNumber
	 * @param {Int} charge
	 * @param {Int} explicitValence
	 * @returns {Int}
	 */
	getImplicitHydValence: function(atomicNumber, charge, explicitValence)
	{
		var elem = atomicNumber;
		var q = charge;
		var val = explicitValence;
		
	  var impval = 0;
	  if (elem == 6) { // C
	    impval = 4 - abs(q);
	  } else if (elem == 7 || elem == 15) { // N or P
	    impval = 3 + q;
	  } else if (elem == 8 || elem == 16) { // O or S
	    impval = 2 + q;
	  }
	  if (impval < 0) {
	    impval = 0;
	  }
	  if (val > impval) {
	    impval = val;
	  }
	  return impval;
	}
};

// defaultly the valence determination method is MDL.
Kekule.ValenceUtils.getImplicitValence = Kekule.ValenceUtils.getImplicitMdlValence;