#!/usr/bin/perl

use lib 'd:/Programs/Perl/lib';
use lib 'c:/Programs/Perl/lib';
#use lib 'd:/MyWebs/cgi-bin/lib';

use lib '/home/tkamiya/bin/lib';
use lib '/home/tkamiya/bin';

use Utils;
use ProgVars;
use MyApplication;
use Crystal::CIF;
use Crystal::Crystal;
use Crystal::AtomType;

use strict;
#use warnings;


my $ProgramDir      = ProgVars::ProgramDir(); #"d:\\Programs";
my $BinDir          = ProgVars::BinDir();
my $DBDir           = ProgVars::PeriodicTableDir();

my $RietanFPDir         = ProgVars::RietanFPDir();
my $RietanFPProgramPath = Deps::MakePath($RietanFPDir, "RIETAN_VENUS", 0);

my $SpaceGroupDBPath     = Deps::MakePath($RietanFPDir, ["RIETAN_VENUS", "SPGRA"], 0);
my $SPGRDBPath           = Deps::MakePath($RietanFPDir, ["RIETAN_VENUS", "spgr.daf"], 0);
my $ASFDCPath            = Deps::MakePath($RietanFPDir, ["RIETAN_VENUS", "asfdc"], 0);


my $NonrelInputPath           = Deps::MakePath($DBDir, "nonrel",                      0);
my $IonRadius1DBPath          = Deps::MakePath($DBDir, "IonRadius1.html",             0);
my $IonRadius2DBPath          = Deps::MakePath($DBDir, "IonRadius2.html",             0);
my $PeriodicTable1DBPath      = Deps::MakePath($DBDir, "PeriodicTable1.html",         0);
my $PeriodicTable2DBDir       = Deps::MakePath($DBDir, "PeriodicTable2",              0);
my $PeriodicTable3DB          = Deps::MakePath($DBDir, "PERIODIC.CSV",                0);
my $ElectronicConfigurationDB = Deps::MakePath($DBDir, "ElectronicConfiguration.csv", 0);

my $MXDDir     = ProgVars::MXDDir();
my $MXDExecDir = ProgVars::MXDExecDir();
my $SX1DBPath  = ProgVars::SX1DBPath();

my $LF = "\n";

my $OutputDBDir = Deps::MakePath($DBDir, 'atoms', 0);


my $in = JFile->new($NonrelInputPath, 'r') or die "$!";
for(my $i = 1 ; ; $i++) {
# H  HFS ATOM CALC.
#    1  300    1
#   1.00000   0.97804  20.00000  32.00000   0.00000
#  1.0  0.0  0.0   -0.30       1.0
	my $line1 = $in->ReadLine();  #    1  300    1
	last if(!$line1);

	my ($atomname) = ($line1 =~ /^\s*(.*?)\s/);
	$atomname = ucfirst lc $atomname;
	last if($atomname eq '');

	my $DBPath = Deps::MakePath($OutputDBDir, sprintf("%03d-%s.ini", $i, $atomname), 0);
	print("i=$i: $atomname  saved to [$DBPath]\n");

	my ($patomdb, $pmaterialdb, $pbusingdb) = &GetAtomDBHash($atomname, 0);
	my $out = JFile->new($DBPath, 'w') or die $!;
	$out->print("[Atom]\n");
	foreach my $key (sort keys %$patomdb) {
		print("  $key: $patomdb->{$key}\n");
		if($key eq 'pIonRadius') {
			my $p = $patomdb->{$key};
			my $val = join(',', @$p);
#			$out->print("$key=$val\n");
			}
		else {
			$out->print("$key=$patomdb->{$key}\n");
		}
	}
	$out->print("\n");
	$out->print("[Busing]\n");
	foreach my $key (sort keys %$pbusingdb) {
		print("  $key: $pbusingdb->{$key}\n");
		$out->print("$key=$pbusingdb->{$key}\n");
	}
	$out->print("\n");
	$out->print("[Material]\n");
	foreach my $key (sort keys %$pmaterialdb) {
		print("  $key: $pmaterialdb->{$key}\n");
		$out->print("$key=$pmaterialdb->{$key}\n");
	}
	$out->Close();

	while(1) {
		my $line2 = $in->ReadLine();     #   1.00000   0.97804  20.00000
		last if(!$line2 or Utils::DelSpace($line2) eq '');
	}
}
$in->Close();

exit;

sub ReadASFParameters
{
	my ($this, $AtomName, $asfdcfile, $XraySource, $StopByError) = @_;
	$asfdcfile = $ASFDCPath if(!defined $asfdcfile or $asfdcfile eq '');
	$StopByError = 1 if(!defined $StopByError);
#print "AtomName=[$AtomName]  Path=[$ASFDCPath]\n";

	my $in = new JFile($asfdcfile, "r");
	if(!$in) {
		print "Can not read ASF for [$AtomName] from [$asfdcfile].\n";
exit if($StopByError);
		return undef;
	}
	my $ReadAtomName;
	while(!$in->eof()) {
		my $line = $in->ReadLine();
		last if($in->eof());
		my ($n) = Utils::Split("\\s+", $line);
		if(uc $n eq uc $AtomName) { #$line =~ /^\s*$AtomName\s/i) {
			$ReadAtomName = $line;
			last;
		}
	}
#print "Atom: [$AtomName] $ReadAtomName";
	my $line1 = $in->ReadLine();
	my $line2 = $in->ReadLine();
	my @a1 = Utils::Split("\\s+", $line1);
	if(@a1 <= 9) {
#		$a1[9] = 0.0;
	}
	my @a2 = Utils::Split("\\s+", $line2);
	if(@a2 == 11) {
		@a1 = ($a2[0], $a2[6], $a2[1], $a2[7], $a2[2], $a2[8], $a2[3], $a2[9], $a2[4], $a2[10], $a2[5]);
		$line2 = $in->ReadLine();
	}
	else {
		@a1 = ($a1[0], $a1[1], $a1[2], $a1[3], $a1[4], $a1[5], $a1[6], $a1[7], 0.0, 1.0, $a1[8]);
	}

#	my @all = @a1;
	my @a3;
	if($line2 !~ /0\//) {
		@a3 = Utils::Split("[,\\s]+", $line2);
#		@all = (@a1, @a3);
#print "a1=", join(', ', @a1), "\n";
#print "a3=", join(', ', @a3), "\n";
	}

	$in->Close();
#	return undef if(!defined $line2);
if(!defined $line2) {
	print "Error in Rietan::ReadASFParameters: Can not find ASF for [$AtomName].\n";
	exit if($StopByError);
}

	my ($atomname) = ($ReadAtomName =~ /^(.[a-z]?)/);
	my ($AtomicNumber, $aname, $charge) = AtomType::GetAtomInformation($atomname);
	$this->{AtomicNumber} = $AtomicNumber;
#print "[$ReadAtomName - $atomname] ($AtomicNumber, $aname, $charge)\n";
#print "ASF: $atomname: [$a1[0],$a1[1]] [$a1[2],$a1[3]] [$a1[4],$a1[5]] [$a1[6],$a1[7]] [$a1[8],$a1[9]] [$a1[10]]\n";


#print "S=$XraySource\n";
	if(defined $XraySource) {
		my ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b) = @a1;
		my ($Crdf1, $Crdf2, $Fedf1, $Fedf2, $Codf1, $Codf2, $Cudf1,$Cudf2, 
			$Modf1, $Modf2, $Agdf1, $Agdf2, $Kbdf1, $Kbdf2) = @a3;
#		my ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,
#			$Crdf1, $Crdf2, $Fedf1, $Fedf2, $Codf1, $Codf2, $Cudf1,$Cudf2, 
#			$Modf1, $Modf2, $Agdf1, $Agdf2, $Kbdf1, $Kbdf2) = @all;
#print "S=$XraySource: atm=$atomname: Cu=$Cudf1, $Cudf2\n";
		if($XraySource eq 'Cr' and defined $Crdf2) {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Crdf1,$Crdf2);
		}
		elsif($XraySource eq 'Fe' and defined $Fedf2) {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Fedf1,$Fedf2);
		}
		elsif($XraySource eq 'Co' and defined $Codf2) {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Codf1,$Codf2);
		}
		elsif($XraySource eq 'Cu' and defined $Cudf2) {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Cudf1,$Cudf2);
		}
		elsif($XraySource eq 'Mo' and defined $Modf2) {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Modf1,$Modf2);
		}
		elsif($XraySource eq 'Ag' and defined $Agdf2) {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Agdf1,$Agdf2);
		}
		elsif($XraySource eq 'Kb' and defined $Kbdf2) {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b,$Kbdf1,$Kbdf2);
		}
		else {
			@a1 = ($A1, $B1, $A2, $B2, $A3, $B3, $A4, $B4, $A5, $B5, $C, $b);
		}
	}
	else {
	}
	$this->{pASFDCParameters} = \@a1;
	$this->{ASFDCAtomName}    = $AtomName;
if(@a1 < 11) {
	print "Error in Rietan::ReadASFParameters: Can not find ASF for [$AtomName].\n";
	exit if($StopByError);
}
	return @a1;
}

sub ReadSpaceGroup
{
	my ($this, $ispg, $iset, $IsPrint) = @_;
print "SPGDBPath: $SpaceGroupDBPath\n" if($IsPrint);
	return 0 unless(open(IN,"<$SpaceGroupDBPath"));

	while(<IN>) {
		my $line = $_;
		my ($iSPG, $iSet, $LaueG, $nCentr, $nSym, $SPGName) 
			= ($line =~ /^\s*?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\d+?)\s+?(\S.*)$/);
#print "line: $line<br>";
#print "i: $iSPG ($iSet) - $ispg ($iset)<br>\n";
		last if(!defined $iSPG or $iSPG < 1);
		unless($iSPG == $ispg and $iSet == $iset) {
			my $ICONDLine = <IN>;
			for(my $i = 0 ; $i < $nSym ; $i++) {
				my $SymOp = <IN>;
			}
			next;
		}

#print "iSPG: $iSPG\n";
#print "iCenter: $nCentr\n";
		$this->{iLaueG}  = $LaueG;
		$this->{iCenter} = $nCentr;

		my $SPG = new SpaceGroup();
		$SPG->SetSPGName($SPGName);
		$SPG->SetiSPG($iSPG);
		$SPG->SetiSet($iSet);
		$SPG->SetiLaueGroup($LaueG);
		$SPG->AnalyzeTranslation();

		my $ICONDLine = <IN>;
		my @ICOND = unpack("a2a2a2a2a2a2a2a2a2a2a2a2a2a2", $ICONDLine);
		$SPG->SetRietanDiffractinCondition(@ICOND);
#		for(my $i = 0 ; $i < 14 ; $i++) {
#			my $type = SpaceGroup::ICONDTypeStrByRietanIndex($i);
#			my $str  = SpaceGroup::ICONDCondStrByRietanIndex($i);
#			printf "      %3s: %s${LF}", $type, $str
#					if($ICOND[$i] > 0);
#		}

		for(my $i = 0 ; $i < $nSym ; $i++) {
			my $SymOp = <IN>;
			Utils::DelSpace($SymOp);
			$SPG->AddSymmetryOperation($SymOp);
#print "symop: $SymOp<br>\n";
#			my @SymOpXYZ = split(/,\s*/, $SymOp);
#			my @XMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[0]);
#			my @YMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[1]);
#			my @ZMatrix = SpaceGroup::SymOpToMatrix($SymOpXYZ[2]);
		}

		$SPG->ExpandSymmetryOperation($nCentr);
		close(IN);
		return $SPG;
	}

	close(IN);
	return 0;
}

sub ReadHermannMauguin
{
	my ($this, $ispg, $iset) = @_;
print "SPGRDBPath: $SPGRDBPath\n";

	my $in = JFile->new($SPGRDBPath, 'r') or return undef;

	while(1) {
		my $line = $in->ReadLine();
		last if(!defined $line);

		my ($iSPG, $str, $otherSPGs) = ($line =~ /\(\s*(\d+)\s*\)\s*(\S.*\S)\s+(\d+)\s*$/);
#print "line: $line\n";
#print "i: $iSPG [$str] $otherSPGs\n";
		next if(!defined $iSPG);
		next if($iSPG != $ispg);

		my @a;
		$a[0] = substr($str,  0, 12);
		$a[1] = substr($str, 12, 12);
		$a[2] = substr($str, 24, 12);
		$a[3] = substr($str, 36, 12);
		for(my $i = 0 ; $i < 4 ; $i++) {
			last if(!defined $a[$i]);
			Utils::DelSpace($a[$i]);
		}
#print "  a=", join('], [', @a), "\n";
		my $HM = $a[$iset-1];
#print "Hit: $iSPG=$iSPG($iset): [$HM]\n";
		return $HM;
	}
}


sub GetAtomicNumber 
{
	my ($name, $Debug) = (@_);

	$name =~ s/\{.*?\}//g;
	$name =~ s/\d//g;
	$name = uc $name;
	$name =~ s/^(\D+?)\d.*$/$1/;
	my $an = -1;
	unless(open(IN, "<$NonrelInputPath")) {
		print "Error: $!: $NonrelInputPath${LF}";# if($Debug);
		return -1;
	}

	while(<IN>) {
# H  HFS ATOM CALC.
#    1  300    1
#   1.00000   0.97804  20.00000  32.00000   0.00000
#  1.0  0.0  0.0   -0.30       1.0
  		if($_ =~ /^\s*$name\s/) { # H  HFS ATOM CALC.
			my $line = <IN>;  #    1  300    1
			$line = <IN>;     #   1.00000   0.97804  20.00000
			($an) = ($line =~ /^\s*(.*?)\s/);
			last;
		}
	}
	close(IN);
	return $an;
}


sub GetAtomDBHash {
	my ($element, $charge, $nCoordination) = @_;
	$charge = 0 if(!defined $charge);

	if($element =~ /^\d+$/) {
		$element = AtomType::GetAtomName($element);
	}

	my ($mass, $charge0, $ai, $bi, $ci, $rad) = AtomType::GetBusingParameter($element);
	my ($AtmNum, $JName, $EName, $NameOrigin) = AtomType::GetIonInfFromPeriodicTable1($element);
	my ($AtomicNumber, $AtomName, $Charge)    = AtomType::GetAtomInformation($element);
	my $CationRadius = AtomType::GetCationRadius($element, $charge, $nCoordination);
	my @IonRadius    = AtomType::GetIonRadius2($element, $charge, $nCoordination);
	my ($filepath, $AtomJName, $AtomEName,
		$AtomicMass, $FoundYear, $AtomicRadius,
		$MeltingPoint, $BoilingPoint, $Density,
		$HeatCapacity, $IonizationPotential, $ElectronAffinity) = AtomType::GetIonInfFromPeriodicTable2($AtmNum);
	my $NameOrigin2;
	($AtmNum, $JName, $EName, $NameOrigin2) = AtomType::GetIonInfFromPeriodicTable1($element);
	my ($pOrbitalName1, $pnElectron1)       = AtomType::GetElectronicConfiguraton($AtmNum);
	my ($pOrbitalName2, $pnElectron2)       = AtomType::SpeculateElectronicConfiguration($AtmNum);
	my $ElectronConfiguration1 = '';
	my $ElectronConfiguration2 = '';
	if($pOrbitalName1) {
		for(my $i = 0 ; $i < @$pOrbitalName1 ; $i++) {
			next if($pnElectron1->[$i] == 0);
			$ElectronConfiguration1 .= "$pOrbitalName1->[$i]($pnElectron1->[$i])";
		}
		for(my $i = 0 ; $i < @$pOrbitalName2 ; $i++) {
			next if($pnElectron2->[$i] == 0);
			$ElectronConfiguration2 .= "$pOrbitalName2->[$i]($pnElectron2->[$i])";
		}
	}
#print "  $ElectronConfiguration1\n";
#print "  $ElectronConfiguration2\n";

	$AtomicMass = $mass        if(!defined $AtomicMass);
	$JName      = $AtomJName   if(!defined $JName);
	$EName      = $AtomEName   if(!defined $EName);
	$NameOrigin = $NameOrigin2 if(!defined $NameOrigin);

	my %atomdb = (
		name                   => $element,
		Z                      => $AtmNum,
		mass                   => $AtomicMass,
		charge                 => $charge,
#		nCoordination          => $nCoordination,
		AtomicRadius           => $AtomicRadius,
#		CationRadius           => $CationRadius,
		pIonRadius             => \@IonRadius,
		ElectronConfiguration1 => $ElectronConfiguration1,
		ElectronConfiguration2 => $ElectronConfiguration2,
		JName                  => $JName,
		EName                  => $EName,
		NameOrigin             => $NameOrigin,
		NameOrigin2 => $NameOrigin2,
		FoundYear              => $FoundYear,
		);

	my %materialdb = (
		IonizationPotential    => $IonizationPotential,
		ElectronAffinity       => $ElectronAffinity,
		MeltingPoint           => $MeltingPoint,
		BoilingPoint           => $BoilingPoint,
		Density                => $Density,
		HeatCapacity           => $HeatCapacity,
		);

	my %busingdb = (
		ai                     => $ai,
		bi                     => $bi,
		ci                     => $ci,
		rad => $rad,
		charge => $charge0,
		);

	return \%atomdb, \%materialdb, \%busingdb;
}

