//!----------------------------------------------------------------------
//!----------------------------------------------------------------------
//! Copyright (C) 2003, 2004, 2005
//!      Chaok Seok, Evangelos Coutsias, Matthew Jacobson, and Ken Dill.
//!      UCSF, Univeristy of New Mexico, Seoul National University
//!
//! This library is free software; you can redistribute it and/or
//! modify it under the terms of the GNU Lesser General Public
//! License as published by the Free Software Foundation; either
//! version 2.1 of the License, or (at your option) any later version.
//!
//! This library is distributed in the hope that it will be useful,
//! but WITHOUT ANY WARRANTY; without even the implied warranty of
//! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//! Lesser General Public License for more details.
//!
//! You should have received a copy of the GNU Lesser General Public
//! License along with this library; if not, write to the Free Software
//! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//!----------------------------------------------------------------------------
//! written by Chaok Seok, 2003
//!-----------------------------------------------------------------------
//!-----------------------------------------------------------------------
//program main_pep
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

#include "sturm.h"
#include "in_out.h"
#include "tripep_closure.h"

int main()
 {
//!-----------------------------------------------------------------------
//! This is a sample driver routine to reconstruct tripeptide loops
//! from the coordinates in a pdb file using a canonical bond lengths and
//! angles.
//!-----------------------------------------------------------------------
//  use in_out
//  use tripep_closure
//!-----------------------------------------------------------------------
//  implicit none
//  real(dp) :: time1, time2
//  character(len=100) :: in_pdb, out_prefix, out_pdb
  char in_pdb[100], out_prefix[100], out_pdb[100];
//  character(len=4) :: res_name(5)
  char res_name[5][4];
//  integer :: n0, n_soln, unit = 17, i, j, k, n1, n2, order(max_soln)
  int n0, n_soln, i, j, k, n1, n2;
//  real(dp) :: r_n(3,5), r_a(3,5), r_c(3,5)
  double r_n[5][3], r_a[5][3], r_c[5][3];
//  real(dp) :: r_soln_n(3,3,max_soln), r_soln_a(3,3,max_soln), r_soln_c(3,3,max_soln)
  double r_soln_n[max_soln][3][3], r_soln_a[max_soln][3][3], r_soln_c[max_soln][3][3];
//  real(dp) :: rmsd, sum, dr(3)
  double rmsd, sum, dr[3];
//  real(dp) :: r0_n(3,3), r0_a(3,3), r0_c(3,3)
  double r0_n[3][3], r0_a[3][3], r0_c[3][3];
  
//  logical :: calc_rmsd, write_out_pdb
  int  calc_rmsd, write_out_pdb;
//  real(dp) :: b_len(6), b_ang(7), t_ang(2)
  double b_len[6], b_ang[7], t_ang[2];

//  ! input parameters (lengths)
//  real(dp), parameter :: b_na = 1.45d0, b_ac = 1.52d0, b_cn = 1.33d0
  double b_na = 1.45e0, b_ac = 1.52e0, b_cn = 1.33e0;
//  ! input parameters (angles in radians)
//  real(dp), parameter :: ang_nac = 111.6*deg2rad, ang_acn = 117.5*deg2rad
  double ang_nac = 111.6*deg2rad, ang_acn = 117.5*deg2rad;
//  real(dp), parameter :: ang_cna = 120.0*deg2rad
  double ang_cna = 120.0*deg2rad;

//!-----------------------------------------------------------------------

//  call my_timer(time1)

//  !! initialize: set up input parameters
//  ! bond lengths
//  b_len(1:6) = (/ b_ac, b_cn, b_na, b_ac, b_cn, b_na /)
  b_len[0]=b_ac;
  b_len[1]=b_cn;
  b_len[2]=b_na;
  b_len[3]=b_ac;
  b_len[4]=b_cn;
  b_len[5]=b_na;
  
//  ! bond angles
//  b_ang(1:7) = (/ ang_nac, ang_acn, ang_cna, ang_nac, ang_acn, ang_cna, ang_nac /)
  b_ang[0]=ang_nac;
  b_ang[1]=ang_acn;
  b_ang[2]=ang_cna;
  b_ang[3]=ang_nac;
  b_ang[4]=ang_acn;
  b_ang[5]=ang_cna;
  b_ang[6]=ang_nac;
   
//  ! peptide torsion angles
//  t_ang(1:2) = pi
  t_ang[0] = pi;
  t_ang[1] = pi;
//  call initialize_loop_closure(b_len, b_ang, t_ang)
  initialize_loop_closure(b_len, b_ang, t_ang);

//  ! output options
//  calc_rmsd = .true.
  calc_rmsd = 1;
//  write_out_pdb = .false.
  write_out_pdb = 1;

//  ! input pdb file and residue number
//  in_pdb = 'data/135l.pdb'
  strcpy(in_pdb,"data/135l.pdb");
//  n1 = 2
  n1 = 2;
//  n2 = 2
  n2 = 2;

//  write(*,900)
//  write(*,*) "Input pdb file name ="
//  write(*,*) trim(in_pdb)
//  write(*,*) "initial and final residue number ="
//  write(*,*) n1, n2
//  write(*,900)

//  out_prefix = in_pdb(1:len(trim(in_pdb))-4)??'_loop'
  strcpy(out_prefix,"data/135l_loop");
     
//  write(*,"(2a10)") 'first res', '# soln'
//  write(*,900)

//  do n0 = n1, n2
  for(n0=n1;n0<=n2;n0++)
   {
//     ! read pdb file to get backbone atoms
//     call read_pdb_backbone(in_pdb, res_name, r_n, r_a, r_c, n0-1, n0+3)
    read_pdb_backbone(in_pdb, res_name, r_n, r_a, r_c, n0-1, n0+3);
     
//     ! save initial coord for rmsd 
//     r0_n(:,:) = r_n(:,2:4)
//     r0_a(:,:) = r_a(:,2:4)
//     r0_c(:,:) = r_c(:,2:4)
    for(i=0;i<3;i++)
      for(j=0;j<3;j++)
       {
        r0_n[i][j]=r_n[i+1][j];
        r0_a[i][j]=r_a[i+1][j];
        r0_c[i][j]=r_c[i+1][j];
       }
//     ! call tripeptide loop closure routine
//     call solv_3pep_poly(r_n(:,2), r_a(:,2), r_a(:,4), r_c(:,4), &
//          r_soln_n, r_soln_a, r_soln_c, n_soln)
    solve_3pep_poly(r_n[1], r_a[1], r_a[3], r_c[3], r_soln_n, r_soln_a, r_soln_c, &n_soln);
//     write(*,"(2i10)") n0, n_soln
    printf("Starting res.: %d Ending res.: %d  No. of soulutions: %d\n", n0, n0+2, n_soln);

//     if (calc_rmsd) then
//        ! backbone coord in pdb 
//        do k = 1, n_soln
    if (calc_rmsd)
     {
      for(k=0;k<n_soln;k++)
       {
//           ! copy coord
//           do i = 2, 4
//              r_n(:,i) = r_soln_n(:,i-1,k)
//              r_a(:,i) = r_soln_a(:,i-1,k)
//              r_c(:,i) = r_soln_c(:,i-1,k)
//           end do
        for(i=0;i<3;i++)
          for(j=0;j<3;j++)
           {
            r_n[i+1][j] = r_soln_n[k][i][j];
            r_a[i+1][j] = r_soln_a[k][i][j];
            r_c[i+1][j] = r_soln_c[k][i][j];
           } 
//           ! rmsd
//           sum = 0.0d0
        sum = 0.0e0;
//           do i = 2, 4
//              dr(:) = r_n(:,i) - r0_n(:,i-1)
//              sum = sum + dot_product(dr,dr)
//              dr(:) = r_a(:,i) - r0_a(:,i-1)
//              sum = sum + dot_product(dr,dr)
//              dr(:) = r_c(:,i) - r0_c(:,i-1)
//              sum = sum + dot_product(dr,dr)
//           end do
        for(i=0;i<3;i++)
	 {
	  for(j=0;j<3;j++)
	    dr[j] = r_soln_n[k][i][j] - r0_n[i][j];
	  sum += dot_product(dr,dr);
	  for(j=0;j<3;j++)
	    dr[j] = r_soln_a[k][i][j] - r0_a[i][j];
	  sum += dot_product(dr,dr);
	  for(j=0;j<3;j++)
	    dr[j] = r_soln_c[k][i][j] - r0_c[i][j];
	  sum += dot_product(dr,dr);
	 }
//           rmsd = sqrt(sum/9.0d0)
        rmsd = sqrt(sum/9.0e0);

//           write(*,"(f15.3)") rmsd
        printf("Rmsd for solution #%d is %.3f\n", k+1, rmsd);

//           if (write_out_pdb) then
//              out_pdb = trim(out_prefix)??'_'??char(ichar('0')+k)??'.pdb'
//              write(*,*) ' Writing soln ', k, ' in file ', trim(out_pdb)
//              call write_pdb_backbone(out_pdb, res_name, r_n, r_a, r_c, n0-1, n0+3)
//           end if
        if(write_out_pdb)
         {
          sprintf(out_pdb, "%s_%d.pdb", out_prefix, k+1);
          printf("Recording the solution #%d in %s\n", k+1, out_pdb);
          write_pdb_backbone(out_pdb, res_name, r_n, r_a, r_c, n0-1, n0+3);
         }

//        end do
       }
//     end if
     }
//  end do
   }
  return 0;
 }

//  write(*,900)
//  call my_timer(time2)
//  write(*,"(A, F10.3, A)") ' Total time elapsed = ', (time2-time1),' sec'
//  write(*,900)

//900 format(' ---------------------------------------------------')

//end program main_pep
//!-----------------------------------------------------------------------
//subroutine my_timer(ttime)
//!-----------------------------------------------------------------------
//  implicit none
//  integer, parameter :: pd = kind(1.0d0)
//  real(pd) :: ttime
//  character(len=8) :: date
//  character(len=10) :: time
//  character(len=5) :: zone
//  integer, dimension(8) :: values
//  integer, dimension(12) :: days_in_month
//  integer :: days
//  days_in_month = (/ 31,28,31,30,31,30,31,31,30,31,30,31 /)
//  call date_and_time(date,time,zone,values)
//  if (mod(values(1),4) == 0) days_in_month(2) = 29
//  days = sum(days_in_month(1:(values(2)-1)))+values(3)
//  ttime = 1.0d-3*(values(8)+1.0d3*(values(7)+ &
//       60*(values(6)+60*(values(5)+24*days))))
//end subroutine my_timer
//!-----------------------------------------------------------------------
