/*
FILE:     ndb_to_cif.C
*/
/*
VERSION:  1.600
*/
/*
DATE:     2/3/2005
*/
/*
  Comments and Questions to: sw-help@rcsb.rutgers.edu
*/
/*
COPYRIGHT 1999-2005 Rutgers - The State University of New Jersey

This software is provided WITHOUT WARRANTY OF MERCHANTABILITY OR
FITNESS FOR A PARTICULAR PURPOSE OR ANY OTHER WARRANTY, EXPRESS OR
IMPLIED.  RUTGERS MAKE NO REPRESENTATION OR WARRANTY THAT THE
SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT OR OTHER
PROPRIETARY RIGHT.

The user of this software shall indemnify, hold harmless and defend
Rutgers, its governors, trustees, officers, employees, students,
agents and the authors against any and all claims, suits,
losses, liabilities, damages, costs, fees, and expenses including
reasonable attorneys' fees resulting from or arising out of the
use of this software.  This indemnification shall include, but is
not limited to, any and all claims alleging products liability.
*/
/*
               PDB SOFTWARE LICENSE AGREEMENT

BY CLICKING THE ACCEPTANCE BUTTON OR INSTALLING OR USING 
THIS "SOFTWARE, THE INDIVIDUAL OR ENTITY LICENSING THE  
SOFTWARE ("LICENSEE") IS CONSENTING TO BE BOUND BY AND IS 
BECOMING A PARTY TO THIS AGREEMENT.  IF LICENSEE DOES NOT 
AGREE TO ALL OF THE TERMS OF THIS AGREEMENT
THE LICENSEE MUST NOT INSTALL OR USE THE SOFTWARE.

1. LICENSE AGREEMENT

This is a license between you ("Licensee") and the Protein Data Bank (PDB) 
at Rutgers, The State University of New Jersey (hereafter referred to 
as "RUTGERS").   The software is owned by RUTGERS and protected by 
copyright laws, and some elements are protected by laws governing 
trademarks, trade dress and trade secrets, and may be protected by 
patent laws. 

2. LICENSE GRANT

RUTGERS grants you, and you hereby accept, non-exclusive, royalty-free 
perpetual license to install, use, modify, prepare derivative works, 
incorporate into other computer software, and distribute in binary 
and source code format, or any derivative work thereof, together with 
any associated media, printed materials, and on-line or electronic 
documentation (if any) provided by RUTGERS (collectively, the "SOFTWARE"), 
subject to the following terms and conditions: (i) any distribution 
of the SOFTWARE shall bind the receiver to the terms and conditions 
of this Agreement; (ii) any distribution of the SOFTWARE in modified 
form shall clearly state that the SOFTWARE has been modified from 
the version originally obtained from RUTGERS.  

2. COPYRIGHT; RETENTION OF RIGHTS.  

The above license grant is conditioned on the following: (i) you must 
reproduce all copyright notices and other proprietary notices on any 
copies of the SOFTWARE and you must not remove such notices; (ii) in 
the event you compile the SOFTWARE, you will include the copyright 
notice with the binary in such a manner as to allow it to be easily 
viewable; (iii) if you incorporate the SOFTWARE into other code, you 
must provide notice that the code contains the SOFTWARE and include 
a copy of the copyright notices and other proprietary notices.  All 
copies of the SOFTWARE shall be subject to the terms of this Agreement.  

3. NO MAINTENANCE OR SUPPORT; TREATMENT OF ENHANCEMENTS 

RUTGERS is under no obligation whatsoever to: (i) provide maintenance 
or support for the SOFTWARE; or (ii) to notify you of bug fixes, patches, 
or upgrades to the features, functionality or performance of the 
SOFTWARE ("Enhancements") (if any), whether developed by RUTGERS 
or third parties.  If, in its sole discretion, RUTGERS makes an 
Enhancement available to you and RUTGERS does not separately enter 
into a written license agreement with you relating to such bug fix, 
patch or upgrade, then it shall be deemed incorporated into the SOFTWARE 
and subject to this Agreement. You are under no obligation whatsoever 
to provide any Enhancements to RUTGERS or the public that you may 
develop over time; however, if you choose to provide your Enhancements 
to RUTGERS, or if you choose to otherwise publish or distribute your 
Enhancements, in source code form without contemporaneously requiring 
end users or RUTGERS to enter into a separate written license agreement 
for such Enhancements, then you hereby grant RUTGERS a non-exclusive,
royalty-free perpetual license to install, use, modify, prepare
derivative works, incorporate into the SOFTWARE or other computer
software, distribute, and sublicense your Enhancements or derivative
works thereof, in binary and source code form.

4. FEES.  There is no license fee for the SOFTWARE.  If Licensee
wishes to receive the SOFTWARE on media, there may be a small charge
for the media and for shipping and handling.  Licensee is
responsible for any and all taxes.

5. TERMINATION.  Without prejudice to any other rights, Licensor
may terminate this Agreement if Licensee breaches any of its terms
and conditions.  Upon termination, Licensee shall destroy all
copies of the SOFTWARE.

6. PROPRIETARY RIGHTS.  Title, ownership rights, and intellectual
property rights in the Product shall remain with RUTGERS.  Licensee 
acknowledges such ownership and intellectual property rights and will 
not take any action to jeopardize, limit or interfere in any manner 
with RUTGERS' ownership of or rights with respect to the SOFTWARE.  
The SOFTWARE is protected by copyright and other intellectual 
property laws and by international treaties.  Title and related 
rights in the content accessed through the SOFTWARE is the property 
of the applicable content owner and is protected by applicable law.  
The license granted under this Agreement gives Licensee no rights to such
content.

7. DISCLAIMER OF WARRANTY.  THE SOFTWARE IS PROVIDED FREE OF 
CHARGE, AND, THEREFORE, ON AN "AS IS" BASIS, WITHOUT WARRANTY OF 
ANY KIND, INCLUDING WITHOUT LIMITATION THE WARRANTIES THAT IT 
IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE 
OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND 
PERFORMANCE OF THE SOFTWARE IS BORNE BY LICENSEE.  SHOULD THE 
SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, THE LICENSEE AND NOT 
LICENSOR ASSUMES THE ENTIRE COST OF ANY SERVICE AND REPAIR.  
THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF 
THIS AGREEMENT.  NO USE OF THE PRODUCT IS AUTHORIZED HEREUNDER 
EXCEPT UNDER THIS DISCLAIMER.

8. LIMITATION OF LIABILITY.  TO THE MAXIMUM EXTENT PERMITTED BY
APPLICABLE LAW,  IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY 
INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 
OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, INCLUDING, 
WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK 
STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL 
OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF ADVISED OF THE
POSSIBILITY THEREOF. 
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>

#include "ndb_misclib.h"
#include "dict_exchange.h"
#include "_maxit.h"
#include "erf_category.h"
#include "erf_util.h"
#include "util.h"

#define N_R_FACTOR  16
#define NKEYWORDS   10
#define MAXIMUM_DB  200

static const char *pdbx_nonpoly_scheme[NKEYWORDS] = {
       "asym_id",
       "entity_id",
       "mon_id",
       "ndb_num",
       "pdb_num",
       "auth_num",
       "pdb_mon_id",
       "auth_mon_id",
       "pdb_id",
       "pdb_ins_code"
};

typedef struct {
        const char *catetory;
        const char *item;
} R_FACTOR;

static R_FACTOR r_factor[N_R_FACTOR] = {
        { "ndb_refine",      "R_factor_all_4sig_cutoff" },
        { "ndb_refine",      "R_factor_all_no_cutoff" },
        { "ndb_refine",      "R_factor_obs_4sig_cutoff" },
        { "ndb_refine",      "R_factor_obs_no_cutoff" },
        { "ndb_refine",      "free_R_factor_4sig_cutoff" },
        { "ndb_refine",      "free_R_factor_no_cutoff" },
        { "refine",          "ls_R_factor_R_free" },
        { "refine",          "ls_R_factor_R_work" },
        { "refine",          "ls_R_factor_all" },
        { "refine",          "ls_R_factor_obs" },
        { "refine_ls_shell", "R_factor_R_free" },
        { "refine_ls_shell", "R_factor_R_work" },
        { "reflns",          "ndb_Rmerge_I_obs" },
        { "reflns",          "ndb_Rsym_value" },
        { "reflns_shell",    "Rmerge_I_obs" },
        { "reflns_shell",    "ndb_Rsym_value" }
};

#define NUM_TML  6
static R_FACTOR tml_token[NUM_TML] = {
        { "RFTPOS",  "tight positional" },
        { "RFMPOS",  "medium positional" },
        { "RFLPOS",  "loose positional" },
        { "RFTTHR",  "tight thermal" },
        { "RFMTHR",  "medium thermal" },
        { "RFLTHR",  "loose thermal" }
};

static ISTable *create_new_table(CIF_CATEGORY *cifcategory);
static ISTable *create_atom_table(CIF_CATEGORY *cifcategory, const int standardized);
static void put_atom_to_atom_site(ISTable *Table, CIF_CATEGORY *cifcategory,
                const int model, const int entity_id, const int card_id,
                const int format, _ATOM *atom, const int standardized);
static void put_atom_to_atom_site_anisotrop(ISTable *Table, CIF_CATEGORY *cifcategory,
                _ATOM *atom, int &row, const int card_id);
static int Insert_Struct_Conf(ISTable *Table, int &nrow, _CHAIN *chain,
           const char *type, const char *ID, const int fst, const int snd,
           const char *clas, const char *comment, const int category_id,
           const int serial_no);
static void Insert_Sheet_Range(ISTable *Table, int &nrow, _CHAIN *chain,
             const char *sheetID, const int initRes, const int endRes,
             const int id, CIF_CATEGORY *category);
static void Insert_Sheet_Hbond(ISTable *Table, int &nrow, _CHAIN *curchain,
             _CHAIN *prevchain, const char *sheetID, const char *curAtom,
             const int curRes, const char *prevAtom, const int prevRes,
             const int id, CIF_CATEGORY *ctg);
static int Insert_Struct_Conn(ISTable *Table, int &nrow, const char *type,
           const char *PDB_id, const char *mod_name, const char *sugar_name,
           const char *atom_id, const char *standard_id, _CHAIN *fst_chain,
           const char *fst_atom, const char *fst_loc, const int fst,
           const char *sym_op1, _CHAIN *snd_chain, const char *snd_atom,
           const char *snd_loc, const int snd, const char *sym_op2,
           _CHAIN *trd_chain, const char *trd_atom, const char *trd_loc,
           const int trd, const char *comment, const int id, const int serial_no);
#ifdef SUN_OS
#ifdef __cplusplus
extern "C" {
#endif
#endif
static int pdb_rev_compare(const void *a, const void *b);
#ifdef SUN_OS
#ifdef __cplusplus
}
#endif
#endif

void _MAXIT::ndb_to_cif_general(const int cif_type, const int transfer,
              const int standardized, const int keep_contact_author,
              const int no_pdbx_strand_id)
{
       int i, j, card_id, id, xray_or_nmr, category_id, ndb_tokenid, ndb_jrnlid;
       int tokenid, rowNo, row, is_ids;
       char buffer[82], WEIGHT[20], *p, *q, db_name[MAXIMUM_DB][20], db_code[MAXIMUM_DB][20];
       double weight;
       _CHAIN *chain = NULL;
       CifString string;
       ISTable *Table = NULL, *Table1 = NULL;
       One_Card_Info_Format *pCard = NULL, *qCard = NULL;
       _RESIDUE *residue = NULL;

       pCard = _CardInfo[FORMUL_TOKEN-1].Head();
       while (pCard) {
            WEIGHT[0] = '\0';
            weight = get_molecule_weight(pCard->Field(2));
            if (weight >= 0.0) 
                 sprintf(WEIGHT, "%11.3f", weight);
            if (strcmp(WEIGHT, "")) {
                 ndb_clean_string(WEIGHT);
                 pCard->AddElementToField(WEIGHT, 4);
            }
            strcpy(buffer, pCard->Field(5));
            p = strstr(buffer, "(");
            q = strstr(buffer, ")");
            if (p && q) {
                 *q = '\0';
                 strcpy(buffer, p + 1);
                 pCard->AddElementToField(buffer, 5);
            }
            if (!strcmp(pCard->Field(2), "HOH")) {
                 qCard = _CardInfo[HETNAM_TOKEN-1].
                    add_a_new_card(NdbToken[HETNAM_TOKEN-1], 0);
                 qCard->AddElementToField(pCard->Field(2), 2);
                 qCard->AddElementToField("WATER", 3);
            }
            pCard = pCard->Next();
       }

       pCard = _CardInfo[REFMET_TOKEN-1].Head();
       if (pCard && (!strncasecmp(pCard->Field(3), "CNS", 3) ||
           !strncasecmp(pCard->Field(3), "X-PLOR", 6))) {
            pCard = _CardInfo[RFACTR_TOKEN-1].Head();
            if (pCard) {
                 if (!strcmp(pCard->Field(10), "") && strcmp(pCard->Field(7), ""))
                      pCard->AddElementToField(pCard->Field(7), 10);
                 else if (strcmp(pCard->Field(10), "") && !strcmp(pCard->Field(7), ""))
                      pCard->AddElementToField(pCard->Field(10), 7);
            }
       }

       card_id = find_card_id("RCSBID");
       if (card_id != -1) {
            pCard = _CardInfo[card_id].Head();
            qCard = _CardInfo[NDBFIL_TOKEN-1].Head();
            if (qCard && strcmp(qCard->Field(1), "")) {
                 if (!pCard)
                      pCard = _CardInfo[card_id].add_a_new_card(NdbToken[card_id], 0);
                 if (!strcmp(pCard->Field(1), ""))
                      pCard->AddElementToField(qCard->Field(1), 1);
            }
       }

       for (i = 0; i < MAXIMUM_DB; i++) {
            db_name[i][0] = '\0';
            db_code[i][0] = '\0';
       }
       id = 0;
       pCard = _CardInfo[DBREF_TOKEN-1].Head();
       while (pCard) {
            for (i = 0; i < id; i++) {
                 if (!strcmp(db_name[i], pCard->Field(7)) &&
                     !strcmp(db_code[i], pCard->Field(9)))
                      break;
            }
            if (i == id) {
                 id++;
                 strcpy(db_name[i], pCard->Field(7));
                 strcpy(db_code[i], pCard->Field(9));
            }
            pCard->AddElementToField(i+1, 15);
            pCard = pCard->Next();
       }

       card_id = find_card_id("SEQADV");
       qCard = _CardInfo[card_id].Head();
       while (qCard) {
            pCard = _CardInfo[DBREF_TOKEN-1].Head();
            while (pCard) {
                 if (!strcmp(pCard->Field(2), qCard->Field(3))) {
                      qCard->AddElementToField(pCard->Field(14), 11);
                      break;
                 }
                 pCard = pCard->Next();
            }
            qCard = qCard->Next();
       }

       card_id = find_card_id("TMLPTL");
       if (card_id >= 0) {
            pCard = _CardInfo[card_id].Head();
            if (!pCard) {
                 for (i = 0; i < NUM_TML; i++) {
                      tokenid = find_card_id(tml_token[i].catetory);
                      if (tokenid < 0) continue;
                      qCard = _CardInfo[tokenid].Head();
                      while (qCard) {
                           pCard = _CardInfo[card_id].
                                add_a_new_card(NdbToken[card_id], 0); 
                           for (j = 1; j < qCard->NumField(); j++)
                                pCard->AddElementToField(qCard->Field(j), j);
                           pCard->AddElementToField(tml_token[i].item, j);
                           qCard = qCard->Next();
                      }
                 }
            }
       }

       xray_or_nmr = 1;
       if (_experiment_type == EXPERIMENT_TYPE_NMR) xray_or_nmr = 2;

       for (category_id = 0; category_id < MxCategory; category_id++) {
            if (transfer && !(transfer & CifCategory[category_id].transfer)) continue;

            if (!(CifCategory[category_id].xray_or_nmr & xray_or_nmr)) continue;

            if (CifCategory[category_id].nkeywords == 0) continue;

            if (cif_type == CIF_NDB_TYPE && !CifCategory[category_id].xyz) continue;
            if (cif_type == CIF_SF_TYPE && !CifCategory[category_id].sf) continue;
            if (cif_type == CIF_COORDENCE_TYPE && 
                      !CifCategory[category_id].coordence) continue;
            if (cif_type == CIF_DEPOSITION_TYPE &&
                      !CifCategory[category_id].deposition) continue;

            ndb_tokenid = -1;
            ndb_jrnlid = -1;
            if (CifCategory[category_id].nkeywords > 1) {
                 for (i = 1; i < CifCategory[category_id].nkeywords; i++) {
                      if (CifCategory[category_id].keywords[i].NdbInfo[0].NdbTokenId
                               > 0) {
                           ndb_tokenid = CifCategory[category_id].keywords[i].
                                         NdbInfo[0].NdbTokenId - 1;
                           if (ndb_tokenid == JRNL_TOKEN-1) {
                                ndb_jrnlid = CifCategory[category_id].keywords[i].
                                         NdbInfo[0].JrnlTokenId -1;
                                if (ndb_jrnlid != -1) break;
                           } else if (ndb_tokenid != -1) break;
                      }
                 }
            } else if (CifCategory[category_id].nkeywords > 0) 
                 ndb_tokenid = CifCategory[category_id].keywords[0].NdbInfo[0].NdbTokenId 
                             - 1;

            if (!strcmp(CifCategory[category_id].category, "atom_site") ||
                !strcmp(CifCategory[category_id].category, "atom_site_anisotrop"))
                 continue;
            else if (!strcmp(CifCategory[category_id].category, "entity_poly"))
                 continue;
            else if (!strcmp(CifCategory[category_id].category, "struct_mon_prot_cis"))
                 continue;
            else if (!strcmp(CifCategory[category_id].category, "struct_asym")) 
                 ndbcif_process_stasym(category_id);      
            else if (!strcmp(CifCategory[category_id].category, "entity_poly_seq")) 
                 ndbcif_process_entity_poly_seq(category_id, no_pdbx_strand_id);      
            else if (!strcmp(CifCategory[category_id].category, "ndb_poly_seq_scheme"))
                 ndbcif_process_asym_poly_seq_ndb(category_id);      
            else if (!strcmp(CifCategory[category_id].category, "refine_ls_restr")) 
                 ndbcif_process_refine_ls_restr(category_id);      
            else if (!strcmp(CifCategory[category_id].category, "struct_site_gen"))
                 ndbcif_process_site_gen(category_id);
            else if (!strcmp(CifCategory[category_id].category, "rcsb_struct_link"))
                 ndbcif_process_rcsb_link(category_id);
            else if (!strcmp(CifCategory[category_id].category, "struct_sheet"))
                 ndbcif_process_struct_sheet(category_id);
            else if (!strcmp(CifCategory[category_id].category, "struct_sheet_order") ||
                     !strcmp(CifCategory[category_id].category, "struct_sheet_range") ||
                     !strcmp(CifCategory[category_id].category, "struct_sheet_hbond") ||
                     !strcmp(CifCategory[category_id].category, "rcsb_struct_sheet_hbond"))
                 continue;
            else if (!strcmp(CifCategory[category_id].category, "struct_conn"))
                 ndbcif_process_struct_conn(category_id);
            else if (!strcmp(CifCategory[category_id].category, "struct_conn_type"))
                 continue;
            else if (!strcmp(CifCategory[category_id].category, "ndb_nonstandard_list"))
                 ndbcif_process_nonstandard_list(category_id);
            else if (!strcmp(CifCategory[category_id].category, "struct_conf"))
                 ndbcif_process_struct_conf(category_id);
            else if (!strcmp(CifCategory[category_id].category, "struct_conf_type"))
                 continue;
            else if (!strcmp(CifCategory[category_id].category, "database_PDB_rev"))
                 ndbcif_process_database_pdb_rev(category_id);
            else if (!strcmp(CifCategory[category_id].category, "database_PDB_rev_record"))
                 continue;
            else if (ndb_tokenid != -1 && NdbToken[ndb_tokenid].MatrixType != 0)
                 ndbcif_process_matrix(category_id);
            else if (ndb_tokenid == JRNL_TOKEN - 1 &&
                    (!strcmp(JrnlToken[ndb_jrnlid].TokenName, "AUTH") &&
                       strcmp(CifCategory[category_id].category, "citation") ||
                     !strcmp(JrnlToken[ndb_jrnlid].TokenName, "EDIT")))
                 ndbcif_process_name(category_id);
            else if (!strcmp(CifCategory[category_id].category, "audit_author"))
                 ndbcif_process_name(category_id);
            else if (ndb_tokenid == PREMRK_TOKEN - 1)
                 ndbcif_process_remark(category_id, ndb_tokenid);
            else if (CifCategory[category_id].general)
                 ndbcif_process_general_category(category_id, ndb_tokenid);
            else ndbcif_process_general(category_id);

            if (!strncmp(CifCategory[category_id].category, "em_", 3)) {
                 Table = _CifObj->GetTablePtr(_StructureId, CifCategory[category_id].category);
                 if (is_empty_table(Table)) continue;
                 rowNo = Table->GetNumRows();
                 for (i = 0; i < CifCategory[category_id].nkeywords; i++) {
                      tokenid = CifCategory[category_id].keywords[i].NdbInfo[0].NdbTokenId-1;
                      if (tokenid >= 0) continue;
                      is_ids = 0;
                      if (strstr(CifCategory[category_id].keywords[i].name, "id")) is_ids = 1;
                      for (j = 0; j < rowNo; j++) {
                           if (is_ids) {
                                sprintf(buffer, "%d", j + 1);
                                string.Copy(buffer);
                           } else string.Copy(".");
                           Table->UpdateCell(string, i, j);
                      }
                 }
                 _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
            }
       }

       ndbcif_postprocessing_molecule_weight();
       ndbcif_postprocessing_exptl_crystal();
       ndbcif_postprocessing_wavelength_id();
       ndbcif_postprocessing_ncs_oper();
       processing_r_factor(0.01);
       ndbcif_postprocessing_cif_standard(standardized, keep_contact_author);

       calculate_all_contact(5.0, 1);
       get_molecule_topology();
       get_ebi_validate_contact();
       get_ebi_validate_bond();
       get_ebi_validate_angle();
       get_ebi_validate_torsion();
       get_ebi_validate_peptide_omega();

       if (!_num_mol) return;
       Table = _CifObj->GetTablePtr(_StructureId, "entity");
       if (is_empty_table(Table)) return;

       rowNo = Table->GetNumRows();
       id = Table->GetColumnIndex("id");
       card_id = Table->GetColumnIndex("type");
       tokenid = Table->GetColumnIndex("ndb_description");

       if (_CifObj->IsTablePresent(_StructureId, "rcsb_entity_nonpoly"))
            _CifObj->DeleteTable(_StructureId, "rcsb_entity_nonpoly");

       Table1 = new ISTable("rcsb_entity_nonpoly");
       Table1->AddColumn("entity_id");
       Table1->AddColumn("name");
       Table1->AddColumn("comp_id");
       row = 0;
       for (i = 0; i < rowNo; i++) {
            Table->GetCell(string, card_id, i);
            if (string == "polymer") continue;
            Table->GetCell(string, id, i);
            chain = _molecules[0]->GetFirstChain();
            while (chain) {
                 if (atoi(string.Text()) == chain->entity_id()) break;
                 chain = _molecules[0]->GetNextChain();
            }
            if (!chain) continue;
            Table1->AddRow();
            Table1->UpdateCell(string, 0, row);
            Table->GetCell(string, tokenid, i);
            Table1->UpdateCell(string, 1, row);
            residue = chain->GetFirstResidue();
            string.Copy(residue->ResName());
            Table1->UpdateCell(string, 2, row);
            row++;
       }
       if (!row) delete Table1;
       else _CifObj->WriteTable(Table1, _StructureId, "rcsb_entity_nonpoly");
}

void _MAXIT::ndbcif_process_general(const int category_id)
{
       int i, j, k, tokenid, fieldno, IsJrnl, nrow, NoKey, SerialNo, logical;
       int comp_id, crystal_id, keyField, found, serialNo1;
       char keyValue[10][82], Value[10][82], value[82];
       CifString string, string1;
       ISTable *Table = NULL;
       One_Card_Info_Format *pCard = NULL, *qCard = NULL;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       nrow = 0;
       Table = create_new_table(&CifCategory[category_id]);
       for (i = 0; i < CifCategory[category_id].nkeywords; i++) {
            NoKey = CifCategory[category_id].nCifKeyField;
            for (j = 0; j < CifCategory[category_id].keywords[i].numNdbInfo; j++) {
                 tokenid = CifCategory[category_id].keywords[i].NdbInfo[j].NdbTokenId-1;
                 fieldno = CifCategory[category_id].keywords[i].NdbInfo[j].NdbFieldNo-1;
                 IsJrnl = FALSE;

                 if (tokenid == JRNL_TOKEN-1) { 
                      tokenid = CifCategory[category_id].keywords[i].NdbInfo[j].JrnlTokenId-1;
                      IsJrnl = TRUE;
                 }
                 if (tokenid < 0 || fieldno < 0) continue;

                 pCard = NULL;
                 if (!IsJrnl) pCard = _CardInfo[tokenid].Head();
                 else pCard = _JrnlCardInfo[tokenid].Head();
                 SerialNo = 0;
                 while (pCard) {
                      if (!strcmp(CifCategory[category_id].category, "struct_ncs_ens_gen") &&
                          !strcmp(pCard->Field(9), "")) {
                           pCard = pCard->Next();
                           continue;
                      }

                      if (pCard == NULL) break;

                      value[0] = '\0';
                      string.Copy(value);
                      logical = FALSE;
                      for (k = 0; k < NoKey; k++) {
                           if (fieldno == CifCategory[category_id].keywords[i].
                                  NdbInfo[j].NdbTokenKeyFieldNo[k])
                                logical = TRUE;
                      }
                      if (IsJrnl) {
                           if (fieldno == 1 && (!strcmp(pCard->Field(fieldno), "") ||
                                   !strcmp(pCard->Field(fieldno), "0")))
                                string.Copy("primary");
                           else string.Copy(pCard->Field(fieldno));
                      } else if (fieldno == 0) {
                           if (strcmp(CifCategory[category_id].keywords[i].NdbInfo[j].
                                      JrnlTokenName_Type, ""))
                                string.Copy(CifCategory[category_id].keywords[i].NdbInfo[j].
                                      JrnlTokenName_Type);
                           else string.Copy(NdbToken[tokenid].TokenName);
                      } else if (logical) {
                           if (strcmp(CifCategory[category_id].keywords[i].NdbInfo[j].
                                JrnlTokenName_Type, "")) {
                                if (strcmp(pCard->Field(fieldno), ""))
                                     sprintf(value, "%s%s", CifCategory[category_id].
                                           keywords[i].NdbInfo[j].JrnlTokenName_Type,
                                           pCard->Field(fieldno));
                                else sprintf(value, "%s1", CifCategory[category_id].
                                           keywords[i].NdbInfo[j].JrnlTokenName_Type);
                           } else {
                                if (strcmp(pCard->Field(fieldno), ""))
                                     sprintf(value, "%s", pCard->Field(fieldno));
                                else strcpy(value, "1");
                           }
                           string.Copy(value);
                      } else {
                           if (tokenid == CRSOLU_TOKEN-1 &&
                               fieldno == 1) {
                                comp_id = 0;
                                crystal_id = atoi(pCard->Field(2));
                                qCard = _CardInfo[tokenid].Head();
                                while (qCard) {
                                     if (atoi(qCard->Field(2)) == crystal_id)
                                          comp_id++;
                                     if (!strcmp(pCard->Field(1), qCard->Field(1)))
                                          break;
                                     qCard = qCard->Next();
                                }
                                sprintf(value, "%d", comp_id);
                                string.Copy(value);
                           } else string.Copy(pCard->Field(fieldno));
                      }

                      if (NoKey) {
                           for (k = 0; k < 10; k++) {
                                keyValue[k][0] = '\0';
                                Value[k][0] = '\0';
                           }

                           for (k = 0; k < NoKey; k++) {
                                keyField = CifCategory[category_id].keywords[i].
                                                NdbInfo[j].NdbTokenKeyFieldNo[k];
                                if (keyField > 0) {
                                     if (IsJrnl) {
                                          if (strcmp(pCard->Field(keyField), "") &&
                                              strcmp(pCard->Field(keyField), "0"))
                                               sprintf(Value[k],"%s", pCard->Field(keyField));
                                          else strcpy(Value[k], "primary");
                                     } else if (strcmp(CifCategory[category_id].keywords[i].
                                           NdbInfo[j].JrnlTokenName_Type, "")) {
                                          if (strcmp(pCard->Field(keyField), ""))
                                               sprintf(Value[k], "%s%s",
                                                   CifCategory[category_id].keywords[i].
                                                   NdbInfo[j].JrnlTokenName_Type,
                                                   pCard->Field(keyField));
                                          else sprintf(Value[k], "%s1",
                                                   CifCategory[category_id].keywords[i].
                                                   NdbInfo[j].JrnlTokenName_Type);
                                     } else {
                                          if (strcmp(pCard->Field(keyField), ""))
                                               sprintf(Value[k],"%s", pCard->Field(keyField));
                                          else strcpy(Value[k], "1");
                                     }
                                } else if (keyField == 0)
                                     strcpy(Value[k], CifCategory[category_id].keywords[i].
                                                       NdbInfo[j].JrnlTokenName_Type);
                           }
                           found = 0;
                           for (serialNo1 = 0; serialNo1 < nrow; serialNo1++) {
                                for (k = 0; k < NoKey; k++) {
                                     keyField = CifCategory[category_id].CifKeyField[k];
                                     Table->GetCell(string1, keyField, serialNo1);
                                     strcpy(keyValue[k], string1.Text());
                                     ndb_clean_string(keyValue[k]);
                                     if (strcmp(keyValue[k], Value[k]) &&
                                         strcmp(Value[k], "")) break;
                                }
                                if (k == NoKey) {
                                     found = 1;
                                     Table->UpdateCell(string, i, serialNo1);
                                }
                           }
                           if (!found) {
                                nrow++;
                                Table->AddRow();
                                Table->UpdateCell(string, i, serialNo1);
                                for (k = 0; k < NoKey; k++) {
                                     keyField = CifCategory[category_id].CifKeyField[k];
                                     string1.Copy(Value[k]);
                                     Table->UpdateCell(string1, keyField, serialNo1);
                                }
                           }
                      } else {
                           if (IsJrnl) 
                                SerialNo = atoi(pCard->Field(JrnlToken[tokenid].SeqField-1));
                           else if (!strcmp(CifCategory[category_id].category, 
                                        "audit_contact_author"))
                                SerialNo = atoi(pCard->Field(NdbToken[tokenid].SeqField-1)) - 1;
                           if (SerialNo >= nrow) {
                                nrow++;
                                Table->AddRow();
                           }
                           Table->UpdateCell(string, i, SerialNo);
                      }
                      pCard = pCard->Next();
                      SerialNo++;
                 }
            }
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndbcif_process_site_gen(const int category_id)
{
       if (_num_mol == 0 || _molecules == NULL) return;
       if (_n_site == 0 || _site == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       ISTable *Table = create_new_table(&CifCategory[category_id]);
       int nrow = 0, i = 0, j = 0, l = 0;
       CifString string;
       char value[10];
       _CHAIN *chain = NULL;
       _FIELD *Init = NULL;
       for (i = 0; i < _n_site; i++) {
            for (j = 0; j < _site[i]->numRes; j++) {
                 chain = _molecules[0]->GetIndexChain(_site[i]->initIndex[j]);
                 if (!chain) continue;
                 Init = chain->SeqResIndex(_site[i]->initRes[j]);
                 if (!Init) continue;

                 Table->AddRow();
                 for (l = 0; l < CifCategory[category_id].nkeywords; l++) {
                      string.Copy("");
                      if (!strcasecmp(CifCategory[category_id].keywords[l].name, "id")) {
                           sprintf(value, "%d", nrow+1);
                           string.Copy(value);
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "site_id")) {
                           string.Copy(_site[i]->SiteID);
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "ndb_num_res")) {
                           sprintf(value, "%d", _site[i]->numRes);
                           string.Copy(value);
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "label_comp_id")) {
                           string.Copy(Init->Field[0]);
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "label_asym_id")) {
                           string.Copy(chain->ChainID());
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "label_seq_id")) {
                           if (chain->chain_type() == ATOMP_TOKEN ||
                               chain->chain_type() == ATOMN_TOKEN)
                                string.Copy(Init->Field[2]);
                           else string.Copy(".");
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "ndb_label_ins_code")) {
                           string.Copy(Init->InsCode);
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "auth_comp_id")) {
                           string.Copy(Init->Field[3]);
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "auth_asym_id")) {
                           string.Copy(chain->PDB_ChainID());
                      } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                                "auth_seq_id")) {
                           string.Copy(Init->Field[4]);
                      }
                      Table->UpdateCell(string, l, nrow);
                 }
                 nrow++;
            }
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndbcif_process_rcsb_link(const int category_id)
{
       if (_num_mol == 0 || _molecules == NULL) return;
       if (_n_link == 0 || _link == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       int nrow = 0, i = 0, l = 0;
       CifString string;
       char value[10];
       _CHAIN *fst = NULL, *snd = NULL;
       _FIELD *Fst = NULL, *Snd = NULL;
       _RESIDUE *fstRes = NULL, *sndRes = NULL;
       ISTable *Table = create_new_table(&CifCategory[category_id]);
       for (i = 0; i < _n_link; i++) {
            fst = _molecules[0]->GetIndexChain(_link[i]->FstIndex);
            snd = _molecules[0]->GetIndexChain(_link[i]->SndIndex);
            if (!fst || !snd) continue;
            Fst = fst->SeqResIndex(_link[i]->FstRes);
            Snd = snd->SeqResIndex(_link[i]->SndRes);
            if (!Fst || !Snd) continue;
            fstRes = Fst->Residue;
            sndRes = Snd->Residue;
            if (!fstRes || !sndRes) continue;
            if (!fstRes->find_atom(_link[i]->FstAtom) ||
                !sndRes->find_atom(_link[i]->SndAtom)) continue;

            Table->AddRow();
            for (l = 0; l < CifCategory[category_id].nkeywords; l++) {
                 string.Copy("");
                 if (!strcasecmp(CifCategory[category_id].keywords[l].name, "id")) {
                      sprintf(value, "%d", nrow+1);
                      string.Copy(value);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr1_label_alt_id")) {
                      string.Copy(_link[i]->altLoc1);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr1_label_asym_id")) {
                      string.Copy(fst->PDB_ChainID());
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr1_label_atom_id")) {
                      string.Copy(_link[i]->FstAtom);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr1_label_comp_id")) {
                      string.Copy(Fst->Field[3]);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr1_label_seq_id")) {
                      string.Copy(Fst->Field[4]);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr1_label_ins_code")) {
                      string.Copy(Fst->InsCode);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr1_symmetry")) {
                      if (strcmp(_link[i]->SymOP_1, ""))
                           string.Copy(_link[i]->SymOP_1);
                      else string.Copy("1_555");
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr2_label_alt_id")) {
                      string.Copy(_link[i]->altLoc2);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr2_label_asym_id")) {
                      string.Copy(snd->PDB_ChainID());
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr2_label_atom_id")) {
                      string.Copy(_link[i]->SndAtom);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr2_label_comp_id")) {
                      string.Copy(Snd->Field[3]);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr2_label_seq_id")) {
                      string.Copy(Snd->Field[4]);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr2_label_ins_code")) {
                      string.Copy(Snd->InsCode);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ptnr2_symmetry")) {
                      if (strcmp(_link[i]->SymOP_2, ""))
                           string.Copy(_link[i]->SymOP_2);
                      else string.Copy("1_555");
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "details")) {
                      string.Copy(_link[i]->details);
                 }
                 Table->UpdateCell(string, l, nrow);
            }
            nrow++;
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndbcif_process_struct_sheet(const int category_id)
{
       int i, nrow1 = 0, nrow2 = 0, nrow3 = 0, nrow4 = 0;
       char sheetID[5], value[10];
       CifString string;
       int serial_sheet = 1;
       _CHAIN *ch1 = NULL, *ch2 = NULL;
       CIF_CATEGORY *cifcategory = NULL, *cifcategory1 = NULL;
       ISTable *Table1 = NULL, *Table2 = NULL, *Table3 = NULL, *Table4 = NULL;

       if (_num_mol == 0 || _molecules == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
            _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);
       Table1 = create_new_table(&CifCategory[category_id]);

       if (_CifObj->IsTablePresent(_StructureId, "struct_sheet_order"))
            _CifObj->DeleteTable(_StructureId, "struct_sheet_order");
       cifcategory = find_category("struct_sheet_order");
       Table2 = create_new_table(cifcategory);

       if (_CifObj->IsTablePresent(_StructureId, "struct_sheet_range"))
            _CifObj->DeleteTable(_StructureId, "struct_sheet_range");
       cifcategory = find_category("struct_sheet_range");
       Table3 = create_new_table(cifcategory);

       if (_CifObj->IsTablePresent(_StructureId, "rcsb_struct_sheet_hbond"))
            _CifObj->DeleteTable(_StructureId, "rcsb_struct_sheet_hbond");
       cifcategory1 = find_category("rcsb_struct_sheet_hbond");
       Table4 = create_new_table(cifcategory1);

       strcpy(sheetID, "xxx");
       for (i = 0; i < _n_sheet; i++) {
            if (strcmp(sheetID, _sheet[i]->sheetID)) {
                 strcpy(sheetID, _sheet[i]->sheetID);
                 serial_sheet = 1;
                 Table1->AddRow();
                 string.Copy(_sheet[i]->sheetID);
                 Table1->UpdateCell(string, 0, nrow1);
                 sprintf(value, "%d", _sheet[i]->numStrands);
                 string.Copy(value);
                 Table1->UpdateCell(string, 2, nrow1);
                 nrow1++;
            } else serial_sheet++;

            ch1 = _molecules[0]->GetIndexChain(_sheet[i]->initIndex);
            Insert_Sheet_Range(Table3, nrow3, ch1, _sheet[i]->sheetID,
                   _sheet[i]->initRes, _sheet[i]->endRes, serial_sheet, cifcategory);

            if (_sheet[i]->sense == 0) continue;
            
            Table2->AddRow();
            string.Copy(_sheet[i]->sheetID);
            Table2->UpdateCell(string, 0, nrow2);
            sprintf(value, "%d", serial_sheet - 1);
            string.Copy(value);
            Table2->UpdateCell(string, 1, nrow2);
            sprintf(value, "%d", serial_sheet);
            string.Copy(value);
            Table2->UpdateCell(string, 2, nrow2);
            if (_sheet[i]->sense > 0)
                 string.Copy("parallel");
            else string.Copy("anti-parallel");
            Table2->UpdateCell(string, 4, nrow2);
            nrow2++;

            if (_sheet[i]->curIndex < 0 || _sheet[i]->prevIndex < 0) continue;

            ch1 = _molecules[0]->GetIndexChain(_sheet[i]->curIndex);
            ch2 = _molecules[0]->GetIndexChain(_sheet[i]->prevIndex);
            Insert_Sheet_Hbond(Table4, nrow4, ch1, ch2, _sheet[i]->sheetID,
                   _sheet[i]->curAtom, _sheet[i]->curRes, _sheet[i]->prevAtom,
                   _sheet[i]->prevRes, serial_sheet, cifcategory1);
       }
       _CifObj->WriteTable(Table1, _StructureId, CifCategory[category_id].category);
       _CifObj->WriteTable(Table2, _StructureId, "struct_sheet_order");
       _CifObj->WriteTable(Table3, _StructureId, "struct_sheet_range");
       _CifObj->WriteTable(Table4, _StructureId, "rcsb_struct_sheet_hbond");
}

void _MAXIT::ndbcif_process_struct_conn(const int category_id)
{
       int exist_ssbond = 0;
       int exist_link = 0;
       int exist_hydbnd = 0;
       int exist_sltbrg = 0;
       int exist_mismat = 0;
       int exist_bspair = 0;
       int exist_modifb = 0;
       int exist_modifp = 0;
       int exist_modifs = 0;
       int exist_modres = 0;

       int nrow = 0, i, j, k, l, num1, num2, hydrog = 0;
       _ATOM **atom1 = NULL, **atom2 = NULL;
       _CHAIN *fst_chain = NULL;
       _CHAIN *snd_chain = NULL;
       _CHAIN *trd_chain = NULL;
       CifString string;
       double dist = 10.0;
       _FIELD *Fst = NULL, *Snd = NULL;
       ISTable *Table = NULL;
       _RESIDUE *fstRes = NULL, *sndRes = NULL;

       if (_num_mol == 0 || _molecules == NULL) return;
       if (!_n_ssbond && !_n_link && !_n_hydbnd && !_n_sltbrg &&
           !_n_mismat && !_n_bspair && !_n_modifb && !_n_modifp &&
           !_n_modifs && !_n_modres) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       Table = create_new_table(&CifCategory[category_id]);
       l = 0;
       for (i = 0; i < _n_ssbond; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_ssbond[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_ssbond[i]->SndIndex);
            if (!fst_chain || !fst_chain) continue; 
            Fst = fst_chain->SeqResIndex(_ssbond[i]->FstRes);
            Snd = snd_chain->SeqResIndex(_ssbond[i]->SndRes);
            if (!Fst || !Snd) continue;
            fstRes = Fst->Residue;
            sndRes = Snd->Residue;
            atom1 = fstRes->find_atom("SG", num1);
            atom2 = sndRes->find_atom("SG", num2);
            for (j = 0; j < num1; j++) {
                 for (k = 0; k < num2; k++) {
                      if (!strcmp(atom1[j]->alt_loc(), atom2[k]->alt_loc()) ||
                          !strcmp(atom1[j]->alt_loc(), "") ||
                          !strcmp(atom2[k]->alt_loc(), "")) {
                           dist = cal_distance(atom1[j], atom2[k]);
                           if (dist < 3.0) {
                                l++;
                                exist_ssbond = Insert_Struct_Conn(Table, nrow, "disulf",
                                    "", "", "", "", "", fst_chain, "SG", atom1[j]->alt_loc(),
                                    _ssbond[i]->FstRes, _ssbond[i]->SymOP_1, snd_chain, "SG",
                                    atom2[k]->alt_loc(), _ssbond[i]->SndRes, _ssbond[i]->SymOP_2,
                                    NULL, "", "", -1, "", category_id, l);
                           } 
                       }
                 }
            }
            if (atom1) delete [] atom1; atom1 = NULL;
            if (atom2) delete [] atom2; atom2 = NULL;
       }

       for (i = 0; i < _n_link; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_link[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_link[i]->SndIndex);
            if (!fst_chain || !fst_chain) continue;
            Fst = fst_chain->SeqResIndex(_link[i]->FstRes);
            Snd = snd_chain->SeqResIndex(_link[i]->SndRes);
            if (!Fst || !Snd) continue;
            fstRes = Fst->Residue;
            sndRes = Snd->Residue;
            if (!fstRes || !sndRes) continue;
            if (!fstRes->find_atom(_link[i]->FstAtom) ||
                !sndRes->find_atom(_link[i]->SndAtom)) continue;
            exist_link = Insert_Struct_Conn(Table, nrow, "covale", "", "",
                   "", "", "", fst_chain, _link[i]->FstAtom, _link[i]->altLoc1,
                   _link[i]->FstRes, _link[i]->SymOP_1, snd_chain, _link[i]->SndAtom,
                   _link[i]->altLoc2, _link[i]->SndRes, _link[i]->SymOP_2, NULL, "",
                   "", -1, _link[i]->details, category_id, i + 1);
       }

       hydrog = 0;
       for (i = 0; i < _n_hydbnd; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_hydbnd[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_hydbnd[i]->SndIndex);
            trd_chain = _molecules[0]->GetIndexChain(_hydbnd[i]->H_Index);
            exist_hydbnd = Insert_Struct_Conn(Table, nrow, "hydrog", "", "",
                   "", "", "", fst_chain, _hydbnd[i]->FstAtom, _hydbnd[i]->altLoc1,
                   _hydbnd[i]->FstRes, _hydbnd[i]->SymOP_1, snd_chain, _hydbnd[i]->SndAtom,
                   _hydbnd[i]->altLoc2, _hydbnd[i]->SndRes, _hydbnd[i]->SymOP_2, trd_chain,
                   _hydbnd[i]->H_Atom, _hydbnd[i]->altLocH, _hydbnd[i]->H_Res, "",
                   category_id, ++hydrog);
       }

       for (i = 0; i < _n_sltbrg; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_sltbrg[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_sltbrg[i]->SndIndex);
            exist_sltbrg = Insert_Struct_Conn(Table, nrow, "saltbr", "", "",
                   "", "", "", fst_chain, _sltbrg[i]->FstAtom, _sltbrg[i]->altLoc1,
                   _sltbrg[i]->FstRes, _sltbrg[i]->SymOP_1, snd_chain, _sltbrg[i]->SndAtom,
                   _sltbrg[i]->altLoc2, _sltbrg[i]->SndRes, _sltbrg[i]->SymOP_2, NULL, "",
                   "", -1, _sltbrg[i]->details, category_id, i + 1);
       }

       for (i = 0; i < _n_mismat; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_mismat[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_mismat[i]->SndIndex);
            exist_mismat = Insert_Struct_Conn(Table, nrow, "mismat",
                   "", "", "", "", "", fst_chain, "", "", _mismat[i]->FstRes,
                   "", snd_chain, "", "", _mismat[i]->SndRes, "", NULL, "",
                   "", -1, "", category_id, i + 1);
       }

       for (i = 0; i < _n_bspair; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_bspair[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_bspair[i]->SndIndex);
            exist_bspair = Insert_Struct_Conn(Table, nrow, "hydrog", "", "",
                   "", "", "", fst_chain, _bspair[i]->FstAtom, "", _bspair[i]->FstRes,
                   "", snd_chain, _bspair[i]->SndAtom, "", _bspair[i]->SndRes,
                   _bspair[i]->Asym_or_Gen, NULL, "", "", -1, _bspair[i]->Type,
                   category_id, ++hydrog);
       }

       for (i = 0; i < _n_modifb; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_modifb[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_modifb[i]->SndIndex);
            exist_modifb = Insert_Struct_Conn(Table, nrow, "covale_base", "",
                   _modifb[i]->Name, "", _modifb[i]->Replaced_Atom, "", fst_chain,
                   _modifb[i]->FstAtom, "", _modifb[i]->FstRes, "", snd_chain,
                   _modifb[i]->SndAtom, "", _modifb[i]->SndRes, "", NULL, "", "", -1,
                   "", category_id, i + 1);
       }

       for (i = 0; i < _n_modifp; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_modifp[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_modifp[i]->SndIndex);
            exist_modifp = Insert_Struct_Conn(Table, nrow, "covale_phosphate",
                   "", _modifp[i]->Name, "", _modifp[i]->Replaced_Atom, "", fst_chain,
                   _modifp[i]->FstAtom, "", _modifp[i]->FstRes, "", snd_chain,
                   _modifp[i]->SndAtom, "", _modifp[i]->SndRes, "", NULL, "", "", -1,
                   "", category_id, i + 1);
       }

       for (i = 0; i < _n_modifs; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_modifs[i]->FstIndex);
            snd_chain = _molecules[0]->GetIndexChain(_modifs[i]->SndIndex);
            exist_modifs = Insert_Struct_Conn(Table, nrow, "covale_sugar", "",
                   _modifs[i]->Name, _modifs[i]->Sugar_Name, _modifs[i]->Replaced_Atom, "",
                   fst_chain, _modifs[i]->FstAtom, "", _modifs[i]->FstRes, "", snd_chain,
                   _modifs[i]->SndAtom, "", _modifs[i]->SndRes, "", NULL, "", "", -1,
                   "", category_id, i + 1);
       }

       for (i = 0; i < _n_modres; i++) {
            fst_chain = _molecules[0]->GetIndexChain(_modres[i]->FstIndex);
            exist_modres = Insert_Struct_Conn(Table, nrow, "modres",
                   _modres[i]->PDB_ID, "", "", "", _modres[i]->Standard_Name, fst_chain,
                   "", "", _modres[i]->FstRes, "", NULL, "", "", -1, "", NULL, "",
                   "", -1, _modres[i]->details, category_id, i + 1);
       }

       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);

       if (exist_ssbond || exist_link || exist_hydbnd || exist_sltbrg ||
           exist_mismat || exist_bspair || exist_modifb || exist_modifp ||
           exist_modifs || exist_modres) {
            CIF_CATEGORY *cifcategory = find_category("struct_conn_type");
            if (_CifObj->IsTablePresent(_StructureId, cifcategory->category))
                 _CifObj->DeleteTable(_StructureId, cifcategory->category);
            Table = create_new_table(cifcategory);
            nrow = 0;

            if (exist_ssbond) {
                 Table->AddRow();
                 string.Copy("disulf");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_link) {
                 Table->AddRow();
                 string.Copy("covale");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_hydbnd || exist_bspair) {
                 Table->AddRow();
                 string.Copy("hydrog");
                 Table->UpdateCell(string, 0, nrow);
                 string.Copy("For hydrogen bonding between nucleic acid bases, donor to acceptor distance of 2.2 -3.5 Angstroms was used.");
                 Table->UpdateCell(string, 1, nrow);
                 nrow++;
            }
            if (exist_sltbrg) {
                 Table->AddRow();
                 string.Copy("saltbr");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_mismat) {
                 Table->AddRow();
                 string.Copy("mismat");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_modifb) {
                 Table->AddRow();
                 string.Copy("covale_base");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_modifp) {
                 Table->AddRow();
                 string.Copy("covale_phosphate");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_modifs) {
                 Table->AddRow();
                 string.Copy("covale_sugar");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_modres) {
                 Table->AddRow();
                 string.Copy("modres");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }

            _CifObj->WriteTable(Table, _StructureId, cifcategory->category);
       }
}

void _MAXIT::ndbcif_process_nonstandard_list(const int category_id)
{
       if (_num_mol == 0 || _molecules == NULL) return;
       if (_n_het == 0 || _het == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       ISTable *Table = create_new_table(&CifCategory[category_id]);
       _CHAIN *chn = NULL;
       _FIELD *Fst = NULL;
       int nrow = 0, i, l;
       char value[10];
       CifString string;
       for (i = 0; i < _n_het; i++) {
            chn = _molecules[0]->GetIndexChain(_het[i]->initIndex);
            if (!chn) continue;
            Fst = chn->SeqResIndex(_het[i]->initRes);
            if (!Fst) continue;
            Table->AddRow();
            for (l = 0; l < CifCategory[category_id].nkeywords; l++) {
                 string.Copy("");
                 if (!strcasecmp(CifCategory[category_id].keywords[l].name, "id")) {
                      string.Copy(Fst->Field[0]);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "label_asym_id")) {
                      string.Copy(chn->ChainID());
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "label_seq_id")) {
                      string.Copy(Fst->Field[2]);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "ins_code")) {
                      string.Copy(Fst->InsCode);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "auth_asym_id")) {
                      string.Copy(chn->PDB_ChainID());
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "auth_seq_id")) {
                      string.Copy(Fst->Field[4]);
                 } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                           "number_atoms_nh")) {
                      sprintf(value, "%d", _het[i]->numAtoms);
                      string.Copy(value);
                 }
                 Table->UpdateCell(string, l, nrow);
            }
            nrow++;
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndbcif_process_struct_conf(const int category_id)
{
       if (_num_mol == 0 || _molecules == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       int exist_helix = 0;
       int exist_turn = 0;
       int helix_num = 1;
       int turn_num = 1;
       ISTable *Table = create_new_table(&CifCategory[category_id]);
       int nrow = 0, j = 0;
       char value[10];
       CifString string;
       _HELIX *helix = NULL;
       _TURN *turn = NULL;
       _CHAIN *chain = _molecules[0]->GetFirstChain();
       while (chain) {
            for (j = 0; j < chain->n_helix(); j++) {
                 helix = chain->helix(j);
                 if (!helix) continue;
                 sprintf(value, "%d", helix->helixClass);
                 exist_helix =Insert_Struct_Conf(Table, nrow, chain,
                      "HELX_P", helix->helixID, helix->initRes, helix->endRes,
                      value, helix->comment, category_id, helix_num);
                 helix_num++;
            }
            for (j = 0; j < chain->n_turn(); j++) {
                 turn = chain->turn(j);
                 if (!turn) continue;
                 exist_turn = Insert_Struct_Conf(Table, nrow, chain,
                      "TURN_P", turn->turnID, turn->initRes, turn->endRes, "",
                      turn->comment, category_id, turn_num);
                 turn_num++;
            }
            chain = _molecules[0]->GetNextChain();
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);

       if (exist_helix || exist_turn) {
            CIF_CATEGORY *cifcategory = find_category("struct_conf_type");
            if (_CifObj->IsTablePresent(_StructureId, cifcategory->category))
                 _CifObj->DeleteTable(_StructureId, cifcategory->category);
            Table = create_new_table(cifcategory);
            nrow = 0;
            if (exist_helix) {
                 Table->AddRow();
                 string.Copy("HELX_P");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            if (exist_turn) {
                 Table->AddRow();
                 string.Copy("TURN_P");
                 Table->UpdateCell(string, 0, nrow);
                 nrow++;
            }
            _CifObj->WriteTable(Table, _StructureId, cifcategory->category);
       }
}

void _MAXIT::ndbcif_process_stasym(const int id)
{
       if (_num_mol == 0 || _molecules == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[id].category);

       ISTable *Table = create_new_table(&CifCategory[id]);

       int nrow = 0, j = 0;
       CifString string;
       char value[10];

       _CHAIN *chain = _molecules[_rep_mol]->GetFirstChain();
       while (chain) {
            Table->AddRow();
            for (j = 0; j < CifCategory[id].nkeywords; j++) {
                 string.Copy("");
                 if (!strcasecmp(CifCategory[id].keywords[j].name, "id"))
                      string.Copy(chain->ChainID());
                 else if (!strcasecmp(CifCategory[id].keywords[j].name, "ndb_pdb_id"))
                      string.Copy(chain->PDB_ChainID());
                 else if (!strcasecmp(CifCategory[id].keywords[j].name, "ndb_alt_id"))
                      string.Copy(chain->PUB_ChainID());
                 else if (!strcasecmp(CifCategory[id].keywords[j].name,
                              "rcsb_blank_PDB_chainid_flag")) {
                      if (!strcmp(chain->PDB_ChainID_Flag(), ""))
                           string.Copy("N");
                      else string.Copy(chain->PDB_ChainID_Flag());
                 } else if (!strcasecmp(CifCategory[id].keywords[j].name, "ndb_type")) {
                      string.Copy(NdbToken[chain->chain_type()-1].TokenName);
                 } else if (!strcasecmp(CifCategory[id].keywords[j].name, "ndb_order")) {
                      value[0] = '\0';
                      if (chain->order() > 0)
                           sprintf(value, "%d", chain->order());
                      string.Copy(value);
                 } else if (!strcasecmp(CifCategory[id].keywords[j].name, "ndb_modified")) {
                      if (chain->isModified())
                           string.Copy("Y");
                      else string.Copy("N");
                 } else if (!strcasecmp(CifCategory[id].keywords[j].name, "entity_id")) {
                      sprintf(value, "%d", chain->entity_id());
                      string.Copy(value);
                 } else if (!strcasecmp(CifCategory[id].keywords[j].name, "details")) {
                      One_Card_Info_Format *pCard = _CardInfo[STASYM_TOKEN-1].Head();
                      while (pCard) {
                           if (!strcmp(pCard->Field(3), chain->ChainID())) break;
                           pCard = pCard->Next();
                      }
                      if (pCard) string.Copy(pCard->Field(5));
                 }
                 Table->UpdateCell(string, j, nrow);
            }
            nrow++;
            chain = _molecules[_rep_mol]->GetNextChain();
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[id].category);
}

void _MAXIT::ndbcif_process_entity_poly_seq(const int id, const int no_pdbx_strand_id)
{
       int j = 0, k = 0, irow = 0, last = 0, len = 0, len1 = 0, nrow = 0;
       int n_entity_id = 0, *entity_id = NULL, len_p = 0, strand_index = -1;
       int target_index = -1;
       char value[10], *code = NULL;
       CifString string, sequence, sequence_p;
       ConnectFormat *drug = NULL;
       _FIELD *SeqRes = NULL;
       _CHAIN *chain = NULL;
       ISTable *Table = NULL, *Table1 = NULL;
       One_Card_Info_Format *pCard = NULL;

       if (_num_mol == 0 || _molecules == NULL) return;

       entity_id = new int[_molecules[0]->Num_Chain()];
       for (j = 0; j < _molecules[0]->Num_Chain(); j++) entity_id[j] = -1;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[id].category))
       _CifObj->DeleteTable(_StructureId, CifCategory[id].category);

       if (_CifObj->IsTablePresent(_StructureId, "entity_poly"))
           _CifObj->DeleteTable(_StructureId, "entity_poly");

       Table = create_new_table(&CifCategory[id]);

       pCard = _CardInfo[TARGET_TOKEN-1].Head();

       Table1 = new ISTable("entity_poly");
       Table1->AddColumn("entity_id");
       Table1->AddColumn("type");
       Table1->AddColumn("nstd_linkage");
       Table1->AddColumn("nstd_monomer");
       Table1->AddColumn("ndb_seq_one_letter_code");
       Table1->AddColumn("ndb_seq_one_letter_code_can");
       if (!no_pdbx_strand_id) {
	    Table1->AddColumn("ndb_chain_id");
            strand_index = 6;
       }
       if (pCard) {
	    Table1->AddColumn("pdbx_target_identifier");
            if (!no_pdbx_strand_id)
                 target_index = 7;
            else target_index = 6;
       }

       chain = _molecules[0]->GetFirstChain();
       while (chain) {
            if (!chain->has_sequence()) {
                 chain = _molecules[0]->GetNextChain();
                 continue;
            }
            for (j = 0; j < n_entity_id; j++) {
                 if (entity_id[j] == chain->entity_id()) break;
            }
            if (j < n_entity_id) {
                 if (!no_pdbx_strand_id) {
                      for (j = 0; j < irow; j++) {
                           Table1->GetCell(string, 0, j);
                           if (atoi(string.Text()) == chain->entity_id()) {
                                Table1->GetCell(string, strand_index, j);
                                if (string == "" || string == "." || string == "?")
                                     string.Copy(chain->PDB_ChainID());
                                else if (strcmp(chain->PDB_ChainID(), "")) {
                                     string += ",";
                                     string += chain->PDB_ChainID();
                                }
                                Table1->UpdateCell(string, strand_index, j);
                                break;
                           }
                      }
                 }
                 chain = _molecules[0]->GetNextChain();
                 continue;
            }

            entity_id[j] = chain->entity_id();
            n_entity_id++;

            Table1->AddRow();
            sprintf(value, "%d", entity_id[j]);
            string.Copy(value);
            Table1->UpdateCell(string, 0, irow);
            if (chain->chain_type() == ATOMP_TOKEN)
                 string.Copy("polypeptide(L)");
            else if (chain->chain_type() == ATOMS_TOKEN)
                 string.Copy("polysaccharide(D)");
            else if (chain->chain_type() == ATOMN_TOKEN) {
                 if (chain->na_type() == ATOMN_TYPE_DNA_ONLY)
                      string.Copy("polydeoxyribonucleotide");
                 else if (chain->na_type() == ATOMN_TYPE_RNA_ONLY ||
                          chain->na_type() == ATOMN_TYPE_TRNA)
                      string.Copy("polyribonucleotide");
                 // else if (chain->na_type() < 0) {
                 else {
                      for (j = 0; j < _n_entity; j++) {
                           if (_entity[j].Entity_ID == chain->entity_id())
                                break;
                      }
                      if (j < _n_entity && _entity[j].Description &&
                         (strstr(_entity[j].Description, "RIBOSOM") ||
                          strstr(_entity[j].Description, "ribiosom") ||
                          strstr(_entity[j].Description, "RNA") ||
                          strstr(_entity[j].Description, "rna")))
                           string.Copy("polyribonucleotide");
                      else string.Copy("polydeoxyribonucleotide");
                 } // else string.Copy("other");
            }
            Table1->UpdateCell(string, 1, irow);
            string.Copy("no");
            Table1->UpdateCell(string, 2, irow);

            last = 0;
            sequence.Copy("");
            sequence_p.Copy("");
            len = 0;
            len_p = 0;
            for (j = 0; j < chain->SeqLen(); j++) {
                 SeqRes = chain->SeqRes(j);
                 if (SeqRes->Deleted) continue;
                 Table->AddRow();
                 code = get_oneletter_code(SeqRes->Field[0]);
                 len1 = strlen(code);
                 if (len1 == 1) {
                      if (len + len1 > 80) {
                           sequence += "\n";
                           len = 0;
                      }
                      sequence += code;
                      len += len1;
                      if (len_p + len1 > 80) {
                           sequence_p += "\n";
                           len_p = 0;
                      }
                      sequence_p += code;
                      len_p += len1;
                 } else if (len1 == 2 && code[0] == '+') {
                      if (len + 1 > 80) {
                           sequence += "\n";
                           len = 0;
                      }
                      sequence += &code[1];
                      len += 1;
                      if (len_p + 1 > 80) {
                           sequence_p += "\n";
                           len_p = 0;
                      }
                      sequence_p += &code[1];
                      len_p += 1;
                 } else {
                      if (len + len1 + 2 > 80) {
                           sequence += "\n";
                           len = 0;
                      }
                      sequence += "(";
                      sequence += code;
                      sequence += ")";
                      len += (len1 + 2);
                      drug = find_drug(code);
                      if (drug) {
                           if (drug->parent_residue() && strcmp(drug->parent_residue(), "")) {
                                code = get_oneletter_code(drug->parent_residue());
                                if (strlen(code) == 1) strcpy(value, code);
                                else strcpy(value, "X");
                           } else strcpy(value, "X");
                      } else strcpy(value, "X");
                      if (len_p + 1 > 80) {
                           sequence_p += "\n";
                           len_p = 0;
                      }
                      sequence_p += value;
                      len_p += 1;
                 }
                 if ((chain->chain_type() == ATOMP_TOKEN ||
                      chain->chain_type() == ATOMN_TOKEN) &&
                     (SeqRes->Field[0][0] == '+' ||
                     !is_a_standard_residue(SeqRes->Field[0]))) {
                      last = 1;
                 }
                 for (k = 0; k < CifCategory[id].nkeywords; k++) {
                      string.Copy("");
                      if (!strcasecmp(CifCategory[id].keywords[k].name, "entity_id")) {
                           sprintf(value, "%d", entity_id[n_entity_id-1]);
                           string.Copy(value);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name, "num")) {
                           sprintf(value, "%d", j + 1);
                           string.Copy(value);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name, "mon_id")) {
                           string.Copy(SeqRes->Field[0]);
                      }
                      Table->UpdateCell(string, k, nrow);
                 }
                 nrow++;
            }
            if (last) string.Copy("yes");
            else string.Copy("no");
            Table1->UpdateCell(string, 3, irow);
            Table1->UpdateCell(sequence, 4, irow);
            Table1->UpdateCell(sequence_p, 5, irow);
            if (!no_pdbx_strand_id) {
                 string.Copy(chain->PDB_ChainID());
                 Table1->UpdateCell(string, strand_index, irow);
            }
            if (target_index > 0) {
                 pCard = _CardInfo[TARGET_TOKEN-1].Head();
                 while (pCard) {
                      if (atoi(pCard->Field(1)) == chain->entity_id()) break;
                      pCard = pCard->Next();
                 }
                 if (pCard) {
                      string.Copy(pCard->Field(2));
                      Table1->UpdateCell(string, target_index, irow);
                 }
	    } 
            irow++;

            chain = _molecules[0]->GetNextChain();
       }
       delete [] entity_id;

       _CifObj->WriteTable(Table, _StructureId, CifCategory[id].category);
       _CifObj->WriteTable(Table1, _StructureId, "entity_poly");
}

void _MAXIT::ndbcif_process_asym_poly_seq_ndb(const int id)
{
       int nrow = 0, j = 0, k = 0;
       char value[10];
       _CHAIN *chain = NULL;
       CifString string;
       _FIELD *SeqRes = NULL;
       ISTable *Table = NULL;

       if (_num_mol == 0 || _molecules == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[id].category))
            _CifObj->DeleteTable(_StructureId, CifCategory[id].category);

       if (_CifObj->IsTablePresent(_StructureId, "pdbx_nonpoly_scheme"))
            _CifObj->DeleteTable(_StructureId, "pdbx_nonpoly_scheme");

       if (_CifObj->IsTablePresent(_StructureId, "ndb_nonpoly_scheme"))
            _CifObj->DeleteTable(_StructureId, "ndb_nonpoly_scheme");

       Table = create_new_table(&CifCategory[id]);
       chain = _molecules[0]->GetFirstChain();
       while (chain) {
            if (!chain->has_sequence()) {
                 chain = _molecules[0]->GetNextChain();
                 continue;
            }
            for (j = 0; j < chain->SeqLen(); j++) {
                 SeqRes = chain->SeqRes(j);
                 if (SeqRes->Deleted) continue;
                 Table->AddRow();
                 for (k = 0; k < CifCategory[id].nkeywords; k++) {
                      string.Copy(""); 
                      if (!strcasecmp(CifCategory[id].keywords[k].name, "id")) {
                           string.Copy(chain->ChainID());
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "entity_id")) {
                           sprintf(value, "%d", chain->entity_id());
                           string.Copy(value);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "seq_id")) {
                           sprintf(value, "%d", j + 1);
                           string.Copy(value);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "mon_id")) {
                           string.Copy(SeqRes->Field[0]);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "ndb_num")) {
                           string.Copy(SeqRes->Field[2]);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "pdb_num")) {
                           if (strcmp(SeqRes->InsCode, "")) {
                                sprintf(value, "%s%s", SeqRes->Field[4],
                                                         SeqRes->InsCode);
                                string.Copy(value);
                           } else string.Copy(SeqRes->Field[4]);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "pdb_ins_code")) {
                           if (strcmp(SeqRes->InsCode, ""))
                                string.Copy(SeqRes->InsCode);
                           else string.Copy(".");
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "auth_num")) {
                           string.Copy(SeqRes->Field[6]);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "pdb_mon_id")) {
                           string.Copy(SeqRes->Field[3]);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "auth_mon_id")) {
                           string.Copy(SeqRes->Field[5]);
                      } else if (!strcasecmp(CifCategory[id].keywords[k].name,
                                   "pdb_id")) {
                           string.Copy(chain->PDB_ChainID());
                      }
                      Table->UpdateCell(string, k, nrow);
                 }
                 nrow++;
            }
            chain = _molecules[0]->GetNextChain();
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[id].category);

       Table = new ISTable("ndb_nonpoly_scheme");
       for (k = 0; k < NKEYWORDS; k++) {
            Table->AddColumn(pdbx_nonpoly_scheme[k]);
       }

       nrow = 0;
       chain = _molecules[0]->GetFirstChain();
       while (chain) {
            if (chain->has_sequence()) {
                 chain = _molecules[0]->GetNextChain();
                 continue;
            }
            for (j = 0; j < chain->SeqLen(); j++) {
                 SeqRes = chain->SeqRes(j);
                 if (SeqRes->Deleted) continue;
                 Table->AddRow();
                 for (k = 0; k < NKEYWORDS; k++) {
                      string.Copy(""); 
                      if (!strcasecmp(pdbx_nonpoly_scheme[k], "asym_id")) {
                           string.Copy(chain->ChainID());
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "entity_id")) {
                           sprintf(value, "%d", chain->entity_id());
                           string.Copy(value);
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "mon_id")) {
                           string.Copy(SeqRes->Field[0]);
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "ndb_num")) {
                           string.Copy(SeqRes->Field[2]);
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "pdb_num")) {
                           if (strcmp(SeqRes->InsCode, "")) {
                                sprintf(value, "%s%s", SeqRes->Field[4],
                                                         SeqRes->InsCode);
                                string.Copy(value);
                           } else string.Copy(SeqRes->Field[4]);
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "pdb_ins_code")) {
                           if (strcmp(SeqRes->InsCode, ""))
                                string.Copy(SeqRes->InsCode);
                           else string.Copy(".");
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "auth_num")) {
                           string.Copy(SeqRes->Field[6]);
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "pdb_mon_id")) {
                           string.Copy(SeqRes->Field[3]);
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "auth_mon_id")) {
                           string.Copy(SeqRes->Field[5]);
                      } else if (!strcasecmp(pdbx_nonpoly_scheme[k], "pdb_id")) {
                           string.Copy(chain->PDB_ChainID());
                      }
                      Table->UpdateCell(string, k, nrow);
                 }
                 nrow++;
            }
            chain = _molecules[0]->GetNextChain();
       }
       _CifObj->WriteTable(Table, _StructureId, "ndb_nonpoly_scheme");
}

void _MAXIT::processing_r_factor(const double factor)
{
       int i, j, rowNo, item_index, irow;
       double temp;
       char value[80];
       CifString string;
       ISTable *Table = NULL;

       for (i = 0; i < N_R_FACTOR; i++) {
            if (!_CifObj->IsTablePresent(_StructureId, r_factor[i].catetory))
                 continue;
            Table = _CifObj->GetTablePtr(_StructureId, r_factor[i].catetory);
            rowNo = Table->GetNumRows();
            item_index = Table->GetColumnIndex(r_factor[i].item);

            for (irow = 0; irow < rowNo; irow++) {
                 if (!Table->GetCell(string, item_index, irow)) {
                      if (string != "" && string != "?" && string != ".") {
                           temp = atof(string.Text()) *factor;
                           sprintf(value, "%.7f", temp);
                           for (j = strlen(value) - 1; j >= 0; j--) {
                                if (value[j] == '0') value[j] = '\0';
                                else break;
                           }
                           string.Copy(value);
                           Table->UpdateCell(string, item_index, irow);
                      }
                 }
            }
            _CifObj->WriteTable(Table, _StructureId, r_factor[i].catetory);
       }
}

void _MAXIT::ndbcif_postprocessing_molecule_weight()
{
       if (_num_mol == 0 || _molecules == NULL) return;

       if (!_CifObj->IsTablePresent(_StructureId, "entity")) return;
       ISTable *Table = _CifObj->GetTablePtr(_StructureId, "entity");

       int rowNo = Table->GetNumRows();
       int id_index = Table->GetColumnIndex("id");
       int wg_index = Table->GetColumnIndex("formula_weight");
       int type = Table->GetColumnIndex("rcsb_nonpoly_type");
       if (id_index < 0 || wg_index < 0) return;

       CifString string;
       char value[20];
       _CHAIN *chain = NULL;
       ConnectFormat *drug = NULL;
       _RESIDUE *residue = NULL;
       for (int irow = 0; irow < rowNo; irow++) {
            Table->GetCell(string, id_index, irow);
            if (string != "" && string != "?" && string != ".") {
                 chain = _molecules[_rep_mol]->GetFirstChain();
                 while (chain) {
                      if (chain->entity_id() == atoi(string.Text())) {
                           if (chain->weight() > 0)
                                sprintf(value, "%.3f", chain->weight());
                           else strcpy(value, "");
                           string.Copy(value);
                           Table->UpdateCell(string, wg_index, irow);
                           if (chain->chain_type() != ATOMP_TOKEN &&
                               chain->chain_type() != ATOMN_TOKEN &&
                               chain->chain_type() != ATOMS_TOKEN &&
                               type >= 0) {
                                residue = chain->GetFirstResidue();
                                if (residue) {
                                     drug = find_drug(residue->ResName());
                                     if (drug) {
                                          string.Copy(drug->AtomType());
                                          Table->UpdateCell(string, type, irow);
                                     } else if (!strcmp(residue->ResName(), "UNL")) {
                                          string.Copy("HETAIN");
                                          Table->UpdateCell(string, type, irow);
                                     }
                                }
                           }
                      }
                      chain = _molecules[_rep_mol]->GetNextChain();
                 }
            }
       }
       _CifObj->WriteTable(Table, _StructureId, "entity");
}

void _MAXIT::ndbcif_postprocessing_exptl_crystal()
{
       if (!_CifObj->IsTablePresent(_StructureId, "exptl_crystal")) return;
       ISTable *Table = _CifObj->GetTablePtr(_StructureId, "exptl_crystal");

       int rowNo = Table->GetNumRows();
       int id_index = Table->GetColumnIndex("id");
       if (id_index < 0) return;

       CifString string;
       char value[10];
       for (int irow = 0; irow < rowNo; irow++) {
            sprintf(value, "%d", irow+1);
            string.Copy(value);
            Table->UpdateCell(string, id_index, irow);
       }
       _CifObj->WriteTable(Table, _StructureId, "exptl_crystal");
}

void _MAXIT::ndbcif_postprocessing_wavelength_id()
{
       if (!_CifObj->IsTablePresent(_StructureId, "diffrn_radiation")) return;
       ISTable *Table = _CifObj->GetTablePtr(_StructureId, "diffrn_radiation");

       int rowNo = Table->GetNumRows();
       int id_index = Table->GetColumnIndex("wavelength_id");
       if (id_index < 0) return;

       CifString string;
       for (int irow = 0; irow < rowNo; irow++) {
            Table->GetCell(string, id_index, irow);
            if (string == "" || string == "?" || string == ".") {
                 string.Copy("1");
                 Table->UpdateCell(string, id_index, irow);
            }
       }
       _CifObj->WriteTable(Table, _StructureId, "diffrn_radiation");
}

void _MAXIT::ndbcif_postprocessing_ncs_oper()
{
       if (!_CifObj->IsTablePresent(_StructureId, "struct_ncs_oper")) return;
       ISTable *Table = _CifObj->GetTablePtr(_StructureId, "struct_ncs_oper");
       if (is_empty_table(Table)) return;

       int rowNo = Table->GetNumRows();
       int code_index = Table->GetColumnIndex("code");
       if (code_index < 0) return;

       CifString string;
       for (int irow = 0; irow < rowNo; irow++) {
            Table->GetCell(string, code_index, irow);
            if (string == "" || string == "?") string.Copy("generate");
            else if (string == "1") string.Copy("given");
            Table->UpdateCell(string, code_index, irow);
       }
       _CifObj->WriteTable(Table, _StructureId, "struct_ncs_oper");
}

void _MAXIT::ndbcif_process_general_category(const int category_id, const int ndb_tokenid)
{
       int irow = 0, i, j, fieldno;
       CifString string;
       ISTable *Table = NULL;
       One_Card_Info_Format *pCard = _CardInfo[ndb_tokenid].Head();

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
            _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);  

       Table = create_new_table(&CifCategory[category_id]);

       while (pCard) {
            Table->AddRow();
            for (i = 0; i < CifCategory[category_id].nkeywords; i++) {
                 for (j = 0; j < CifCategory[category_id].keywords[i].numNdbInfo; j++) {
                      fieldno = CifCategory[category_id].keywords[i].NdbInfo[j].NdbFieldNo-1;
                      if (fieldno < 0) continue;
                      string.Copy(pCard->Field(fieldno));
                      Table->UpdateCell(string, i, irow);
                 }
            }
            irow++;
            pCard = pCard->Next();
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndbcif_process_remark(const int category_id, const int ndb_tokenid)
{
       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
            _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       ISTable *Table = create_new_table(&CifCategory[category_id]);

       int irow = 0, i, j, fieldno;
       CifString string("");
       CifString id("-1");
       One_Card_Info_Format *pCard = _CardInfo[ndb_tokenid].Head();
       while (pCard) {
            if (id != pCard->Field(1)) {
                 if (string != "") {
                      Table->AddRow();
                      for (i = 0; i < CifCategory[category_id].nkeywords; i++) {
                           for (j = 0; j < CifCategory[category_id].keywords[i].numNdbInfo; j++) {
                                fieldno = CifCategory[category_id].keywords[i].NdbInfo[j].NdbFieldNo-1;
                                if (fieldno == 1)
                                     Table->UpdateCell(id, i, irow);
                                else if (fieldno == 2)
                                    Table->UpdateCell(string, i, irow);
                           }
                      }
                      irow++;
                      string.Copy("");
                 }
                 id.Copy(pCard->Field(1));
                 string += pCard->Field(2);
            } else {
                 string += '\n';
                 string += pCard->Field(2);
            }
            pCard = pCard->Next();
       }
       if (string != "") {
            Table->AddRow();
            for (i = 0; i < CifCategory[category_id].nkeywords; i++) {
                 for (j = 0; j < CifCategory[category_id].keywords[i].numNdbInfo; j++) {
                      fieldno = CifCategory[category_id].keywords[i].NdbInfo[j].NdbFieldNo-1;
                      if (fieldno == 1)
                           Table->UpdateCell(id, i, irow);
                      else if (fieldno == 2)
                          Table->UpdateCell(string, i, irow);
                 }
            }
            irow++;
            string.Copy("");
       }

       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndbcif_process_database_pdb_rev(const int category_id)
{
       One_Card_Info_Format *pCard = NULL, *qCard = NULL;
       PDB_REV *pdb_rev = NULL;
       int n_rev = 0, i, j, len, irow = 0;
       char buffer[10], *p;
       CifString string;
       ISTable *Table = NULL, *Table1 = NULL;
       CIF_CATEGORY *cifcategory1 = NULL;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
           _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       Table = create_new_table(&CifCategory[category_id]);

       pCard = _CardInfo[REVDAT_TOKEN-1].Head();
       while (pCard) {
            for (i = 0; i < n_rev; i++)
                 if (atoi(pCard->Field(1)) == pdb_rev[i].num) break;
            if (i == n_rev) {
                 n_rev++;
                 pdb_rev = (PDB_REV *) realloc(pdb_rev, n_rev * sizeof(PDB_REV));
                 pdb_rev[i].num = atoi(pCard->Field(1));
                 strcpy(pdb_rev[i].date, pCard->Field(3));
                 strcpy(pdb_rev[i].replaces, pCard->Field(4));
                 pdb_rev[i].mod_type = atoi(pCard->Field(5));
                 pdb_rev[i].record = NULL;
            }
            for (j = 6; j < 10; j++) {
                 if (strcmp(pCard->Field(j), "")) {
                      if (pdb_rev[i].record == NULL) {
                           len = strlen(pCard->Field(j))+1;
                           pdb_rev[i].record = (char *) calloc(len, sizeof(char));
                           strcpy(pdb_rev[i].record, pCard->Field(j));
                      } else if (!strstr(pdb_rev[i].record, pCard->Field(j))) {
                           len = strlen(pCard->Field(j)) + 2 +
                                     strlen(pdb_rev[i].record);
                           pdb_rev[i].record = (char *) realloc(pdb_rev[i].record,
                                                 len * sizeof(char));
                           strcat(pdb_rev[i].record, " ");
                           strcat(pdb_rev[i].record, pCard->Field(j));
                      }
                 }
            }
            pCard = pCard->Next();
       }

       if (n_rev > 1) qsort((void *) pdb_rev, n_rev, sizeof(PDB_REV), pdb_rev_compare);

       for (i = 0; i < n_rev; i++) {
            Table->AddRow();
            sprintf(buffer, "%d", pdb_rev[i].num);
            string.Copy(buffer);
            Table->UpdateCell(string, 0, i);
            string.Copy(pdb_rev[i].date);
            Table->UpdateCell(string, 1, i);
            string.Copy(pdb_rev[i].replaces);
            Table->UpdateCell(string, 4, i);
            sprintf(buffer, "%d", pdb_rev[i].mod_type);
            string.Copy(buffer);
            Table->UpdateCell(string, 5, i);
            if (pdb_rev[i].mod_type == 0) {
                 qCard = _CardInfo[HEADER_TOKEN-1].Head();
                 if (qCard && strcmp(qCard->Field(2), "")) {
                      string.Copy(qCard->Field(2));
                      Table->UpdateCell(string, 2, i);
                 }
            }
       }
       if (n_rev == 0 && _CardInfo[HEADER_TOKEN-1].Head() &&
           strcmp(_CardInfo[HEADER_TOKEN-1].Head()->Field(2), "")) {
            Table->AddRow();
            CifString string;
            string.Copy(_CardInfo[HEADER_TOKEN-1].Head()->Field(2));
            Table->UpdateCell(string, 2, 0);
       }

       if (_CifObj->IsTablePresent(_StructureId, "database_PDB_rev_record"))
           _CifObj->DeleteTable(_StructureId, "database_PDB_rev_record");

       cifcategory1 = find_category("database_PDB_rev_record");
       Table1 = create_new_table(cifcategory1);

       irow = 0;
       for (i = 0; i < n_rev; i++) {
            p = pdb_rev[i].record;
            while (p) {
                 Table1->AddRow();
                 sprintf(buffer, "%d", pdb_rev[i].num);
                 string.Copy(buffer);
                 Table1->UpdateCell(string, 0, irow);
                 p = get_word(p, buffer);
                 string.Copy(buffer);
                 Table1->UpdateCell(string, 1, irow);
                 irow++;
            }
       }

       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
       _CifObj->WriteTable(Table1, _StructureId, cifcategory1->category);

       for (i = 0; i < n_rev; i++) {
            if (pdb_rev[i].record) free ((void *) pdb_rev[i].record);
       }
       free ((void *) pdb_rev);
}

void _MAXIT::ndbcif_process_matrix(const int category_id)
{
       int irow = 0, i, j, tokenid, str_len, rowIndex, fieldno, len, serialNo;
       int index = -1, serial_no = 0;
       char TokenName[8];
       CifString string;
       ISTable *Table = NULL;
       One_Card_Info_Format *pCard = NULL;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
            _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       Table = create_new_table(&CifCategory[category_id]);
       Table->AddRow();
       for (i = 0; i < CifCategory[category_id].nkeywords; i++) {
            tokenid = CifCategory[category_id].keywords[i].NdbInfo[0].NdbTokenId-1;
            if (tokenid < 0 || tokenid > MxTokens) continue;

            str_len = strlen(CifCategory[category_id].keywords[i].name);
            pCard = _CardInfo[tokenid].Head();
            if (pCard) {
                 rowIndex = 0;
                 fieldno=CifCategory[category_id].keywords[i].NdbInfo[0].NdbFieldNo-1;
                 if (NdbToken[tokenid].MatrixType != 0 && str_len > 9 &&
                     !strncmp(&CifCategory[category_id].keywords[i].name[str_len-9], 
                                   "vector", 6)) {
                      len = strlen(CifCategory[category_id].keywords[i].name) - 2;
                      rowIndex = atoi(&CifCategory[category_id].keywords[i].name[len]);
                 } else if (NdbToken[tokenid].MatrixType != 0) {
                      for (j = 0; j < str_len - 1; j++)
                           if (CifCategory[category_id].keywords[i].name[j] == '[') break;
                      rowIndex = atoi(&CifCategory[category_id].keywords[i].name[j+1]);
                 }

                 strcpy(TokenName, pCard->Field(0));
                 while (NdbToken[tokenid].MatrixType != 0 && pCard &&
                        rowIndex > atoi(&TokenName[strlen(TokenName)-1])) {
                      pCard = pCard->Next();
                      if (pCard) strcpy(TokenName, pCard->Field(0));
                 }

                 serialNo = 0;
                 while (pCard) {
                      if (serialNo > irow) {
                           irow++;
                           Table->AddRow();
                      }

                      if (fieldno < 0 || fieldno > NdbToken[tokenid].NumField)
                           string.Copy("");
                      else string.Copy(pCard->Field(fieldno));
                      Table->UpdateCell(string, i, serialNo);
                      serialNo++;
                      if (rowIndex == 0 && NdbToken[tokenid].SeqField == 0) break;
                      do {
                           pCard = pCard->Next();
                           if (pCard) {
                                strcpy(TokenName, pCard->Field(0));
                                index = atoi(&TokenName[strlen(TokenName)-1]);
                                if (NdbToken[tokenid].SeqField) {
                                    serial_no = atoi(pCard->Field(NdbToken[tokenid].
                                                SeqField-1));
                                }
                           }
                      } while (pCard && (rowIndex != 0 && rowIndex != index ||
                         NdbToken[tokenid].SeqField == 0 || (serialNo+1) > serial_no));
                 }
            }
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndbcif_process_name(const int category_id)
{
       int is_Jrnl = 0, id_field = 0, irow = -1, i, j, k, fieldno, tokenid;
       int str_len, pos;
       char tmpstring[82];
       CifString id, string;
       ISTable *Table = NULL;
       One_Card_Info_Format *pCard = NULL;
     
       tokenid = CifCategory[category_id].keywords[0].NdbInfo[0].NdbTokenId-1;
       if (tokenid == JRNL_TOKEN-1) {
            tokenid = CifCategory[category_id].keywords[0].NdbInfo[0].JrnlTokenId-1;
            pCard = _JrnlCardInfo[tokenid].Head();
            is_Jrnl = 1;
       } else pCard = _CardInfo[tokenid].Head();

       if (pCard == NULL) return;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
            _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       Table = create_new_table(&CifCategory[category_id]);

       while (pCard) {
            for (i = 0; i < CifCategory[category_id].nkeywords; i++) {
                 if (is_Jrnl && i == id_field) continue;
                 for (j = 0; j <CifCategory[category_id].keywords[i].numNdbInfo; j++) {
                      fieldno = CifCategory[category_id].keywords[i].NdbInfo[j].NdbFieldNo-1;
                      string.Copy("");
                      if (is_Jrnl) {
                           if (!strcmp(pCard->Field(1), "") ||
                               !strcmp(pCard->Field(1), "0"))
                                id.Copy("primary");
                           else id.Copy(pCard->Field(1)); 
                      }
               
                      if (!strcmp(pCard->Field(fieldno), "") && irow >= 0) 
                           Table->UpdateCell(string, i, irow); 
                      else {
                           str_len = strlen(pCard->Field(fieldno));
                           pos = 0;
                           while (pos < str_len) {
                                memset(tmpstring, 0, 82);
                                for (k = pos; k < str_len; k++)
                                     if (pCard->Field(fieldno)[k] == ',') break;
                                strncpy(tmpstring, &pCard->Field(fieldno)[pos], k-pos);
                                if (pCard->Field(fieldno)[k] == ',' && 
                                    pCard->Field(fieldno)[k+1] ==  ' ')
                                     pos = k+2;
                                else pos = k+1; 
                                
                                irow++;
                                Table->AddRow();
                                if (is_Jrnl) Table->UpdateCell(id, id_field, irow);
                                ndb_name_conversion_last_first(tmpstring);
                                string.Copy(tmpstring);
                                Table->UpdateCell(string, i, irow);
                           }
                      }
                 }
            }
            pCard = pCard->Next();
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::ndb_to_cif_coordinates(const int format, const int remove_hydrogen,
              const int standardized, const int is_iupac, const int id_option,
              const int exchange, const int together, const int no_deriv)
{
       if (_num_mol == 0 || _molecules == NULL) return;

       int atom_id = 0, row = 0, card_id = -1, i, l, n_list = 0, num, remove_q;
       int label_index, rowNo;
       char list[100][5], alt_loc[5];
       _ATOM *atom = NULL;
       _CHAIN *chain = NULL;
       _RESIDUE *residue = NULL;
       CIF_CATEGORY *cifcategory = NULL, *cifcategory1 = NULL;
       CifString string, str;
       ISTable *Table = NULL, *Table1 = NULL;

       cifcategory = find_category("atom_site");
       if (_CifObj->IsTablePresent(_StructureId, cifcategory->category))
            _CifObj->DeleteTable(_StructureId, cifcategory->category);
       Table = create_atom_table(cifcategory, standardized);

       cifcategory1 = find_category("atom_site_anisotrop");
       if (_CifObj->IsTablePresent(_StructureId, cifcategory1->category))
       _CifObj->DeleteTable(_StructureId, cifcategory1->category);
       Table1 = create_new_table(cifcategory1);

       remove_q = 0;
       for (l = 0; l < _num_mol; l++) {
            chain = _molecules[l]->GetFirstChain();
            while (chain) {
                 if (is_iupac && chain->chain_type() == ATOMP_TOKEN)
                      chain->labeling_iupac_hydrogen();

                 card_id = chain->chain_type() - 1;
                 residue = chain->GetFirstResidue();
                 while (residue) {
                      if (is_iupac) residue->labeling_iupac_hydrogen();
                      atom = residue->GetFirstAtom();
                      while (atom) {
                           if (atom->is_hydrogen() && remove_hydrogen == 1) {
                                atom = residue->GetNextAtom();
                                continue;
                           }
                           if (!strcmp(atom->atom_type(), "Q")
                                && _experiment_type == EXPERIMENT_TYPE_NMR) {
                                remove_q = 1;
                                atom = residue->GetNextAtom();
                                continue;
                           }
                           atom_id++;
                           atom->set_atnum(atom_id);

                           strcpy(alt_loc, atom->alt_loc());
                           if (!strcmp(alt_loc, "") || !strcmp(alt_loc, "?")) strcpy(alt_loc, ".");
                           for (i = 0; i < n_list; i++) {
                                if (!strcmp(list[i], alt_loc)) break;
                           }
                           if (i == n_list) {
                                strcpy(list[i], alt_loc);
                                n_list++;
                           }

                           put_atom_to_atom_site(Table, cifcategory,
                               _molecules[l]->Mol_ID(), chain->entity_id(),
                               card_id, format, atom, standardized);
                           if (Table1 && atom->is_anisou())
                                put_atom_to_atom_site_anisotrop(Table1,
                                  cifcategory1, atom, row, card_id);
                           atom = residue->GetNextAtom();
                      }
                      residue = chain->GetNextResidue();
                 }
                 chain = _molecules[l]->GetNextChain();
            }
       }
       if (remove_q) ndb_log_message(NDB_MSG_WARN, "Q atoms have been removed");

       if (!Table1->GetNumRows()) {
            delete Table1;
            Table1 = NULL;
       }
       _CifObj->WriteTable(Table, _StructureId, cifcategory->category);

       if (standardized) {
            if (!no_deriv) {
                 if (together) get_derived_features(_CifObj);
                 else {
                      char *p, tmpFile[100], tmpFile1[300], templateFileName[9] = "./XXXXXX";
                      CifString ids[3];
                      strcpy(tmpFile, templateFileName);
                      int fd = mkstemp(tmpFile);
                      close (fd);
                      CifFileObj *fobj = new CifFileObj(tmpFile, WRITE_MODE);
                      get_derived_features(fobj);
                      num = get_pdb_ndb_ids(id_option, ids);
                      int order = fobj->GetBlockOrder(_StructureId);
                      if (exchange) {
                           for (l = 0; l < num; l++) {
                                fobj->RenameBlock(ids[l].Text(), order);
                                sprintf(tmpFile1, "%s-deriv.cif", ids[l].Text());
                                ndb_set_string_to_lower(tmpFile1);
                                fobj->Write(tmpFile1);
                           }
                      } else {
                           if (ids[0] != "") fobj->RenameBlock(ids[0].Text(), order);
                           strcpy(tmpFile1, _input_filename);
                           p = strstr(tmpFile1, ".");
                           if (p) *p = '\0';
                           strcat(tmpFile1, "-deriv.cif");
                           fobj->Write(tmpFile1);
                      }
                      sprintf(tmpFile1, "rm -f %s", tmpFile);
                      system(tmpFile1);
                      delete fobj;
                 }
            }
       }

       _CifObj->DeleteTable(_StructureId, "atom_sites_alt");
       ISTable *Table2 = new ISTable("atom_sites_alt");
       Table2->AddColumn("id");
       Table2->AddColumn("details");
       for (i = 0; i < n_list; i++) {
            Table2->AddRow();
            string.Copy(list[i]);
            Table2->UpdateCell(string, 0, i);
       }
       _CifObj->WriteTable(Table2, _StructureId, "atom_sites_alt");

       if (Table1) {
            label_index = Table1->GetColumnIndex("ndb_label_alt_id");
            rowNo = Table1->GetNumRows();
            for (i = 0; i < rowNo; i++) {
                 Table1->GetCell(string, label_index, i);
                 if (string == "?" || string == "") {
                      string.Copy(".");
                      Table1->UpdateCell(string, label_index, i);
                 }
            }
            _CifObj->WriteTable(Table1, _StructureId, cifcategory1->category);
       }
}

void _MAXIT::open_mmcif_file()
{
       if (_CifObj) delete _CifObj;
       if (_is_binary)
            _CifObj = new CifFileObj(_output_filename, WRITE_MODE);
       else {
            get_temp_file();
            _CifObj = new CifFileObj(_temp_file, WRITE_MODE);
       }
}

void _MAXIT::write_mmcif_file(const int standardized, const int id_option, const int exchange)
{
       int id_idx, num, numCategory, i, j, k, rowNo, order, no_find_name = 0;
       char **categoryName = NULL, buffer[20], Name[100];
       ISTable *Table = NULL;
       CifString string, id, ids[3];

       if (!_CifObj || _is_binary) return;

       if (standardized || exchange) {
            num = get_pdb_ndb_ids(id_option, ids);
            if (!num) {
                 no_find_name = 1;
                 num = 1;
                 ids[0].Copy(_StructureId);
            }
            if (exchange) {
                 set_exchange_status(INTERNAL_TO_EXCHANGE);
                 _CifObj = dictionary_exchange(_CifObj, _temp_file);
            }
            order = _CifObj->GetBlockOrder(_StructureId);
            categoryName = _CifObj->GetTableNames(numCategory);
            strcpy(Name, _StructureId);
            for (k = 0; k < num; k++) {
                 Table = _CifObj->GetTablePtr(Name, "entry");
                 id_idx = Table->GetColumnIndex("id");
                 id.Copy(ids[k]);
                 Table->UpdateCell(id, id_idx, 0);
     
                 for (i = 0; i < numCategory; i++) {
                      Table = _CifObj->GetTablePtr(Name, categoryName[i]);
                      id_idx = Table->GetColumnIndex("entry_id");
                      if (id_idx >= 0) {
                           rowNo = Table->GetNumRows();
                           for (j = 0; j < rowNo; j++) {
                                Table->UpdateCell(id, id_idx, j);
                           }
                      }
                 }
                 _CifObj->RenameBlock(ids[k].Text(), order);
                 if (exchange) {
                      if (no_find_name) {
                           _CifObj->Write(_output_filename, 0, 1);
                      } else {
                           sprintf(buffer, "%s.cif.tr", ids[k].Text());
                           ndb_set_string_to_lower(buffer);
                           _CifObj->Write(buffer, 0, 1);
                      }
                 }
                 strcpy(Name, ids[k].Text());
            }
            for (i = 0; i < numCategory; i++) delete categoryName[i];
            delete categoryName;
            if (exchange) return;
       }
       _CifObj->Write(_output_filename, 0, 1);
}

void _MAXIT::ndbcif_process_refine_ls_restr(const int category_id)
{
       int irow = 0, index = 0, pid, i, j, tokenid, fieldno;
       char abbreviation = 'o';
       CifString string;

       if (_CifObj->IsTablePresent(_StructureId, CifCategory[category_id].category))
            _CifObj->DeleteTable(_StructureId, CifCategory[category_id].category);

       ISTable *Table = create_new_table(&CifCategory[category_id]);

       One_Card_Info_Format *pCard = _CardInfo[REFMET_TOKEN-1].Head();
       if (pCard) {
            string.Copy(pCard->Field(3));
            string.ToLower();
            for (pid = 0; pid < mxPrograms; pid++) {
                 if (strstr(string.Text(), programs[pid].program)) {
                      abbreviation = programs[pid].abbreviation[0];
                      break;
                 }
            }
       }

       for (i = 0; i < mxRmsRecords; i++) {
            if (rmsRecords[i].type[0] == abbreviation && rmsRecords[i].type[1] == '_') {
                 string.Copy(rmsRecords[i].type);
                 Table->AddRow();
                 index = 0;
                 Table->UpdateCell(string, index, irow);
                 index++;
                 for (j = 0; j < NDB_CIF_RMS_ITEMS; j++) {
                      tokenid = rmsRecords[i].tokens[j];
                      fieldno = rmsRecords[i].fields[j] ;
                      if (tokenid < 0 || tokenid >= MxTokens || fieldno < 0 ||
                          fieldno >= NdbToken[tokenid].NumField)
                           string.Copy("");
                      else {
                           pCard = _CardInfo[tokenid].Head();
                           if (pCard == NULL) string.Copy("");
                           else string.Copy(pCard->Field(fieldno));
                      }
                      Table->UpdateCell(string, index, irow);
                      index++;
                 }
                 irow++;
            }
       }
       _CifObj->WriteTable(Table, _StructureId, CifCategory[category_id].category);
}

void _MAXIT::cif_process_revdat()
{
       int i, irow, irow1 = 0, revised_index[4], rowNo, num_index;
       char buffer[20], value[20];
       CifString string;
       ISTable *Table = NULL, *Table1 = NULL;
       CIF_CATEGORY *cifcategory1 = NULL;
       
       Table = _CifObj->GetTablePtr(_StructureId, "database_PDB_rev_record");
       if (!is_empty_table(Table)) return;

       Table = _CifObj->GetTablePtr(_StructureId, "database_PDB_rev");
       if (is_empty_table(Table)) return;

       rowNo = Table->GetNumRows();
       num_index = Table->GetColumnIndex("num");
       if (num_index < 0) return;
       revised_index[0] = Table->GetColumnIndex("rcsb_record_revised_1");
       revised_index[1] = Table->GetColumnIndex("rcsb_record_revised_2");
       revised_index[2] = Table->GetColumnIndex("rcsb_record_revised_3");
       revised_index[3] = Table->GetColumnIndex("rcsb_record_revised_4");

       _CifObj->DeleteTable(_StructureId, "database_PDB_rev_record");
       cifcategory1 = find_category("database_PDB_rev_record");
       Table1 = create_new_table(cifcategory1);

       for (irow = 0; irow < rowNo; irow++) {
            get_value(string, Table, num_index, irow);
            strcpy(buffer, string.Text());
            for (i = 0; i < 4; i++) {
                 if (revised_index[i] < 0) continue;
                 get_value(string, Table, revised_index[i], irow);
                 if (string == "") continue;
                 strcpy(value, string.Text());

                 string.Copy("");
                 Table->UpdateCell(string, revised_index[i], irow);

                 Table1->AddRow();
                 string.Copy(buffer);
                 Table1->UpdateCell(string, 0, irow1);
                 string.Copy(value);
                 Table1->UpdateCell(string, 1, irow1);
                 irow1++;
            }
       }

       _CifObj->WriteTable(Table1, _StructureId, "database_PDB_rev_record");
}

int _MAXIT::get_pdb_ndb_ids(const int id_option, CifString ids[3])
{
       int i, id_idx, code_idx, rowNo, count = 0;
       CifString string, id;
       ISTable *Table = NULL;

       for (i = 0; i < 3; i++) ids[i].Clear();
       Table = _CifObj->GetTablePtr(_StructureId, "database_2");
       if (is_empty_table(Table)) return count;
       id_idx = Table->GetColumnIndex("database_id");
       code_idx = Table->GetColumnIndex("database_code");
       rowNo = Table->GetNumRows();
       for (i = 0; i < rowNo; i++) {
            Table->GetCell(string, id_idx, i);
            if ((id_option & 1) && (string == "PDB") ||
                (id_option & 2) && (string == "NDB") ||
                (id_option & 4) && (string == "RCSB")) {
                 Table->GetCell(id, code_idx, i);
                 ids[count].Copy(id);
                 count++;
            }
       }
       return count;
}

static ISTable *create_new_table(CIF_CATEGORY *cifcategory)
{
       ISTable *Table = new ISTable(cifcategory->category);
       for (int i = 0; i < cifcategory->nkeywords; i++)
            Table->AddColumn(cifcategory->keywords[i].name);
       return Table;
}

static ISTable *create_atom_table(CIF_CATEGORY *cifcategory, const int standardized)
{
       ISTable *Table = new ISTable(cifcategory->category);
       for (int i = 0; i < cifcategory->nkeywords; i++) {
            if (standardized &&
               (!strcasecmp(cifcategory->keywords[i].name, "ndb_auth_seq_id") ||
                !strcasecmp(cifcategory->keywords[i].name, "ndb_auth_comp_id") ||
                !strcasecmp(cifcategory->keywords[i].name, "ndb_auth_asym_id") ||
                !strcasecmp(cifcategory->keywords[i].name, "ndb_auth_atom_name") ||
                !strcasecmp(cifcategory->keywords[i].name, "footnote_id")))
                 continue;
            Table->AddColumn(cifcategory->keywords[i].name);
       }
       return Table;
}

static void put_atom_to_atom_site(ISTable *Table, CIF_CATEGORY *cifcategory,
                    const int model, const int entity_id, const int card_id,
                    const int format, _ATOM *atom, const int standardized)
{
       int i, row, tmp_id, col;
       char value[80];
       CifString string;

       row = Table->GetNumRows();
       Table->AddRow();
       col = 0;
       for (i = 0; i < cifcategory->nkeywords; i++) {
            string.Copy("");
            if (!strcmp(cifcategory->keywords[i].name, "ndb_model")) {
                 sprintf(value, "%d", model);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "group_PDB")) {
                 if (format == NDB_FILE_FORMAT_PDB) {
                      tmp_id = get_atom_card_id(card_id);
                      string.Copy(AtomInfo[tmp_id].PdbTitle);
                 } else string.Copy(NdbToken[card_id].TokenName);
            } else if (!strcmp(cifcategory->keywords[i].name, "id")) {
                 sprintf(value, "%d", atom->atnum());
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "type_symbol"))
                 string.Copy(atom->atom_type());
            else if (!strcmp(cifcategory->keywords[i].name, "label_atom_id"))
                 string.Copy(atom->atmtype());
            else if (!strcmp(cifcategory->keywords[i].name, "label_alt_id")) {
                 string.Copy(atom->alt_loc());
                 if (string == "?" || string == "") string.Copy(".");
            } else if (!strcmp(cifcategory->keywords[i].name, "label_comp_id"))
                 string.Copy(atom->restype());
            else if (!strcmp(cifcategory->keywords[i].name, "label_asym_id"))
                 string.Copy(atom->chnid());
            else if (!strcmp(cifcategory->keywords[i].name, "label_entity_id")) {
                 sprintf(value, "%d", entity_id);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "label_seq_id")) {
                 if (card_id == ATOMP_TOKEN-1 || card_id == ATOMN_TOKEN-1) {
                      sprintf(value, "%d", atom->resnum());
                      string.Copy(value);
                 } else string.Copy(".");
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_label_seq_num")) {
                 sprintf(value, "%d", atom->resnum());
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_ins_code"))
                 string.Copy(atom->ins_code());
            else if (!strcmp(cifcategory->keywords[i].name, "Cartn_x")) {
                 sprintf(value, "%8.3f", atom->orig().x);
                 ndb_clean_string(value);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "Cartn_y")) {
                 sprintf(value, "%8.3f", atom->orig().y);
                 ndb_clean_string(value);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "Cartn_z")) {
                 sprintf(value, "%8.3f", atom->orig().z);
                 ndb_clean_string(value);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "occupancy")) {
                 sprintf(value, "%6.2f", atom->occ());
                 ndb_clean_string(value);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "B_iso_or_equiv")) {
                 sprintf(value, "%6.2f", atom->t_fct());
                 ndb_clean_string(value);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "Cartn_x_esd")) {
                 if (atom->is_sigatm()) {
                      sprintf(value, "%8.3f", atom->sigatm().sig_x);
                      ndb_clean_string(value);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "Cartn_y_esd")) {
                 if (atom->is_sigatm()) {
                      sprintf(value, "%8.3f", atom->sigatm().sig_y);
                      ndb_clean_string(value);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "Cartn_z_esd")) {
                 if (atom->is_sigatm()) {
                      sprintf(value, "%8.3f", atom->sigatm().sig_z);
                      ndb_clean_string(value);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "occupancy_esd")) {
                 if (atom->is_sigatm()) {
                      sprintf(value, "%6.2f", atom->sigatm().sig_o);
                      ndb_clean_string(value);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "B_iso_or_equiv_esd")) {
                 if (atom->is_sigatm()) {
                      sprintf(value, "%6.2f", atom->sigatm().sig_t);
                      ndb_clean_string(value);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "footnote_id")) {
                 if (standardized) continue;
                 if (atom->footnote() != -10000) {
                      sprintf(value, "%d", atom->footnote());
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_not_in_asym"))
                 string.Copy(atom->not_in_asym());
            else if (!strcmp(cifcategory->keywords[i].name, "auth_seq_id")) {
                 if (strcmp(atom->ins_code(), ""))
                      sprintf(value, "%d%s", atom->pdb_resnum(), atom->ins_code());
                 else sprintf(value, "%d", atom->pdb_resnum());
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "auth_comp_id"))
                 string.Copy(atom->pdb_resnam());
            else if (!strcmp(cifcategory->keywords[i].name, "auth_asym_id"))
                 string.Copy(atom->pdb_chnid());
            else if (!strcmp(cifcategory->keywords[i].name, "auth_atom_id"))
                 string.Copy(atom->pdb_atmnam());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_seq_id")) {
                 if (standardized) continue;
                 sprintf(value, "%d", atom->pub_resnum());
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_comp_id")) {
                 if (standardized) continue;
                 string.Copy(atom->pub_resnam());
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_asym_id")) {
                 if (standardized) continue;
                 string.Copy(atom->pub_chnid());
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_atom_name")) {
                 if (standardized) continue;
                 string.Copy(atom->pub_atmnam());
            }
            Table->UpdateCell(string, col, row);
            col++;
       }
}

static void put_atom_to_atom_site_anisotrop(ISTable *Table, CIF_CATEGORY *cifcategory,
                   _ATOM *atom, int &row, const int card_id)
{
       int i;
       char value[80];
       CifString string;

       Table->AddRow();
       row++;
       for (i = 0; i < cifcategory->nkeywords; i++) {
            string.Copy("");
            if (!strcmp(cifcategory->keywords[i].name, "id")) {
                 sprintf(value, "%d", atom->atnum());
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "type_symbol"))
                 string.Copy(atom->atom_type());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_label_atom_id"))
                 string.Copy(atom->atmtype());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_label_alt_id"))
                 string.Copy(atom->alt_loc());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_label_comp_id"))
                 string.Copy(atom->restype());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_label_asym_id"))
                 string.Copy(atom->chnid());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_label_seq_num")) {
                 if (card_id == ATOMP_TOKEN-1 || card_id == ATOMN_TOKEN-1) {
                      sprintf(value, "%d", atom->resnum());
                      string.Copy(value);
                 } else string.Copy(".");
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_label_ins_code"))
                 string.Copy(atom->ins_code());
            else if (!strcmp(cifcategory->keywords[i].name, "U[1][1]")) {
                 sprintf(value, "%.4f", atom->anisou().u11 / 10000.0);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "U[1][2]")) {
                 sprintf(value, "%.4f", atom->anisou().u12 / 10000.0);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "U[1][3]")) {
                 sprintf(value, "%.4f", atom->anisou().u13 / 10000.0);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "U[2][2]")) {
                 sprintf(value, "%.4f", atom->anisou().u22 / 10000.0);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "U[2][3]")) {
                 sprintf(value, "%.4f", atom->anisou().u23 / 10000.0);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "U[3][3]")) {
                 sprintf(value, "%.4f", atom->anisou().u33 / 10000.0);
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "U[1][1]_esd")) {
                 if (atom->is_siguij()) {
                      sprintf(value, "%.4f", atom->siguij().sig_u11 / 10000.0);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "U[1][2]_esd")) {
                 if (atom->is_siguij()) {
                      sprintf(value, "%.4f", atom->siguij().sig_u12 / 10000.0);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "U[1][3]_esd")) {
                 if (atom->is_siguij()) {
                      sprintf(value, "%.4f", atom->siguij().sig_u13 / 10000.0);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "U[2][2]_esd")) {
                 if (atom->is_siguij()) {
                      sprintf(value, "%.4f", atom->siguij().sig_u22 / 10000.0);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "U[2][3]_esd")) {
                 if (atom->is_siguij()) {
                      sprintf(value, "%.4f", atom->siguij().sig_u23 / 10000.0);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "U[3][3]_esd")) {
                 if (atom->is_siguij()) {
                      sprintf(value, "%.4f", atom->siguij().sig_u33 / 10000.0);
                      string.Copy(value);
                 }
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_not_in_asym"))
                 string.Copy(atom->not_in_asym());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_PDB_residue_no")) {
                 if (strcmp(atom->ins_code(), ""))
                      sprintf(value, "%d%s", atom->pdb_resnum(), atom->ins_code());
                 else sprintf(value, "%d", atom->pdb_resnum());
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_PDB_residue_name"))
                 string.Copy(atom->pdb_resnam());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_PDB_strand_id"))
                 string.Copy(atom->pdb_chnid());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_PDB_atom_name"))
                 string.Copy(atom->pdb_atmnam());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_seq_id")) {
                 sprintf(value, "%d", atom->pub_resnum());
                 string.Copy(value);
            } else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_comp_id"))
                 string.Copy(atom->pub_resnam());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_asym_id"))
                 string.Copy(atom->pub_chnid());
            else if (!strcmp(cifcategory->keywords[i].name, "ndb_auth_atom_name"))
                 string.Copy(atom->pub_atmnam());
            Table->UpdateCell(string, i, row-1);
       }
}

static int Insert_Struct_Conf(ISTable *Table, int &nrow, _CHAIN *chain,
        const char *type, const char *ID, const int fst, const int snd,
        const char *clas, const char *comment, const int category_id,
        const int serial_no)
{
       int l;
       char value[50];
       CifString string;

       _FIELD *Fst = chain->SeqResIndex(fst);
       _FIELD *Snd = chain->SeqResIndex(snd);
       if (!Fst || !Snd) return 0;
       Table->AddRow();
       for (l = 0; l < CifCategory[category_id].nkeywords; l++) {
            string.Copy("");
            if (!strcasecmp(CifCategory[category_id].keywords[l].name, "conf_type_id")) {
                 string.Copy(type);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name, "id")) {
                 sprintf(value, "%s%d", type, serial_no);
                 string.Copy(value);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "pdb_id")) {
                 string.Copy(ID);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "beg_label_comp_id")) {
                 string.Copy(Fst->Field[0]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "beg_label_asym_id")) {
                 string.Copy(chain->ChainID());
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "beg_label_seq_id")) {
                 string.Copy(Fst->Field[2]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "ndb_beg_label_ins_code_pdb")) {
                 string.Copy(Fst->InsCode);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "end_label_comp_id")) {
                 string.Copy(Snd->Field[0]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "end_label_asym_id")) {
                 string.Copy(chain->ChainID());
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "end_label_seq_id")) {
                 string.Copy(Snd->Field[2]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "ndb_end_label_ins_code_pdb")) {
                 string.Copy(Snd->InsCode);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "beg_auth_comp_id")) {
                 string.Copy(Fst->Field[3]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "beg_auth_asym_id")) {
                 string.Copy(chain->PDB_ChainID());
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "beg_auth_seq_id")) {
                 if (strcmp(Fst->InsCode, "")) {
                      sprintf(value, "%s%s", Fst->Field[4], Fst->InsCode);
                      string.Copy(value);
                 } else string.Copy(Fst->Field[4]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "end_auth_comp_id")) {
                 string.Copy(Snd->Field[3]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "end_auth_asym_id")) {
                 string.Copy(chain->PDB_ChainID());
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "end_auth_seq_id")) {
                 if (strcmp(Snd->InsCode, "")) {
                      sprintf(value, "%s%s", Snd->Field[4], Snd->InsCode);
                      string.Copy(value);
                 } else string.Copy(Snd->Field[4]);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "ndb_helix_class_pdb")) {
                 string.Copy(clas);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "details")) {
                 string.Copy(comment);
            } else if (!strcasecmp(CifCategory[category_id].keywords[l].name,
                      "ndb_length")) {
                 if (!strcmp(type, "HELX_P")) {
                      sprintf(value, "%d", snd - fst + 1);
                      string.Copy(value);
                 }
            }
            Table->UpdateCell(string, l, nrow);
       }
       nrow++;
       return 1;
}

static void Insert_Sheet_Range(ISTable *Table, int &nrow, _CHAIN *chain,
             const char *sheetID, const int initRes, const int endRes, 
             const int id, CIF_CATEGORY *category)
{
       int l;
       char value[50];
       CifString string;
       _FIELD *Init = chain->SeqResIndex(initRes);
       _FIELD *End = chain->SeqResIndex(endRes);
       if (!Init || !End) return;
       Table->AddRow();
       for (l = 0; l < category->nkeywords; l++) {
            string.Copy("");
            if (!strcasecmp(category->keywords[l].name, "sheet_id")) {
                 string.Copy(sheetID);
            } else if (!strcasecmp(category->keywords[l].name, "id")) {
                 sprintf(value, "%d", id);
                 string.Copy(value);
            } else if (!strcasecmp(category->keywords[l].name, "beg_label_comp_id")) {
                 string.Copy(Init->Field[0]);
            } else if (!strcasecmp(category->keywords[l].name, "beg_label_asym_id")) {
                 string.Copy(chain->ChainID());
            } else if (!strcasecmp(category->keywords[l].name, "beg_label_seq_id")) {
                 string.Copy(Init->Field[2]);
            } else if (!strcasecmp(category->keywords[l].name, "ndb_beg_label_ins_code_pdb")) {
                 string.Copy(Init->InsCode);
            } else if (!strcasecmp(category->keywords[l].name, "end_label_comp_id")) {
                 string.Copy(End->Field[0]);
            } else if (!strcasecmp(category->keywords[l].name, "end_label_asym_id")) {
                 string.Copy(chain->ChainID());
            } else if (!strcasecmp(category->keywords[l].name, "end_label_seq_id")) {
                 string.Copy(End->Field[2]);
            } else if (!strcasecmp(category->keywords[l].name, "ndb_end_label_ins_code_pdb")) {
                 string.Copy(End->InsCode);
            } else if (!strcasecmp(category->keywords[l].name, "beg_auth_comp_id")) {
                 string.Copy(Init->Field[3]);
            } else if (!strcasecmp(category->keywords[l].name, "beg_auth_asym_id")) {
                 string.Copy(chain->PDB_ChainID());
            } else if (!strcasecmp(category->keywords[l].name, "beg_auth_seq_id")) {
                 if (strcmp(Init->InsCode, "")) {
                      sprintf(value, "%s%s", Init->Field[4], Init->InsCode);
                      string.Copy(value);
                 } else string.Copy(Init->Field[4]);
            } else if (!strcasecmp(category->keywords[l].name, "end_auth_comp_id")) {
                string.Copy(End->Field[3]);
            } else if (!strcasecmp(category->keywords[l].name, "end_auth_asym_id")) {
                 string.Copy(chain->PDB_ChainID());
            } else if (!strcasecmp(category->keywords[l].name, "end_auth_seq_id")) {
                 if (strcmp(End->InsCode, "")) {
                      sprintf(value, "%s%s", End->Field[4], End->InsCode);
                      string.Copy(value);
                 } else string.Copy(End->Field[4]);
            }
            Table->UpdateCell(string, l, nrow);
       }
       nrow++;
}

static void Insert_Sheet_Hbond(ISTable *Table, int &nrow, _CHAIN *curchain,
             _CHAIN *prevchain, const char *sheetID, const char *curAtom,
             const int curRes, const char *prevAtom, const int prevRes,
             const int id, CIF_CATEGORY *ctg)
{
       int l;
       char value[50];
       CifString string;

       _FIELD *Cur = curchain->SeqResIndex(curRes);
       _FIELD *Prev = prevchain->SeqResIndex(prevRes);
       if (!Cur || !Prev || !strcmp(curAtom, "") ||
           !strcmp(prevAtom, "")) return;
       Table->AddRow();
       for (l = 0; l < ctg->nkeywords; l++) {
            string.Copy("");
            if (!strcasecmp(ctg->keywords[l].name, "sheet_id")) {
                 string.Copy(sheetID);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_id_1")) {
                 sprintf(value, "%d", id-1);
                 string.Copy(value);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_id_2")) {
                 sprintf(value, "%d", id);
                 string.Copy(value);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_label_atom_id")) {
                 string.Copy(curAtom);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_label_comp_id")) {
                 string.Copy(Cur->Field[0]);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_label_asym_id")) {
                 string.Copy(curchain->ChainID());
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_label_seq_id")) {
                 string.Copy(Cur->Field[2]);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_PDB_ins_code")) {
                 string.Copy(Cur->InsCode);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_auth_atom_id")) {
                 string.Copy(curAtom);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_auth_comp_id")) {
                 string.Copy(Cur->Field[3]);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_auth_asym_id")) {
                 string.Copy(curchain->PDB_ChainID());
            } else if (!strcasecmp(ctg->keywords[l].name, "range_2_auth_seq_id")) {
                 if (strcmp(Cur->InsCode, "")) {
                      sprintf(value, "%s%s", Cur->Field[4], Cur->InsCode);
                      string.Copy(value);
                 } else string.Copy(Cur->Field[4]);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_label_atom_id")) {
                 string.Copy(prevAtom);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_label_comp_id")) {
                 string.Copy(Prev->Field[0]);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_label_asym_id")) {
                 string.Copy(prevchain->ChainID());
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_label_seq_id")) {
                 string.Copy(Prev->Field[2]);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_PDB_ins_code")) {
                 string.Copy(Prev->InsCode);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_auth_atom_id")) {
                 string.Copy(prevAtom);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_auth_comp_id")) {
                string.Copy(Prev->Field[3]);
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_auth_asym_id")) {
                 string.Copy(prevchain->PDB_ChainID());
            } else if (!strcasecmp(ctg->keywords[l].name, "range_1_auth_seq_id")) {
                 if (strcmp(Prev->InsCode, "")) {
                      sprintf(value, "%s%s", Prev->Field[4], Prev->InsCode);
                      string.Copy(value);
                 } else string.Copy(Prev->Field[4]);
            }
            Table->UpdateCell(string, l, nrow);
       }
       nrow++;
}

static int Insert_Struct_Conn(ISTable *Table, int &nrow, const char *type,
           const char *PDB_id, const char *mod_name, const char *sugar_name,
           const char *atom_id, const char *standard_id, _CHAIN *fst_chain,
           const char *fst_atom, const char *fst_loc, const int fst,
           const char *sym_op1, _CHAIN *snd_chain, const char *snd_atom,
           const char *snd_loc, const int snd, const char *sym_op2,
           _CHAIN *trd_chain, const char *trd_atom, const char *trd_loc,
           const int trd, const char *comment, const int id, const int serial_no)
{
       int l;
       char value[50];
       CifString string;
    
       _FIELD *Fst = NULL;
       _FIELD *Snd = NULL;
       _FIELD *Trd = NULL;
       if (fst_chain) Fst = fst_chain->SeqResIndex(fst);
       if (snd_chain) Snd = snd_chain->SeqResIndex(snd);
       if (trd_chain) Trd = trd_chain->SeqResIndex(trd);
       if (!Fst && !Snd && !Trd) return 0;
       Table->AddRow();
       for (l = 0; l < CifCategory[id].nkeywords; l++) {
            string.Copy("");
            if (!strcasecmp(CifCategory[id].keywords[l].name, "conn_type_id")) {
                 string.Copy(type);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name, "id")) {
                 sprintf(value, "%s%d", type, serial_no);
                 string.Copy(value);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_PDB_id")) {
                 string.Copy(PDB_id);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_ptnr1_mod_name")) {
                 string.Copy(mod_name);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_ptnr1_sugar_name")) {
                 string.Copy(sugar_name);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_ptnr1_replaced_atom")) {
                 string.Copy(atom_id);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ptnr1_label_comp_id")) {
                 string.Copy(Fst->Field[0]);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ptnr1_label_asym_id")) {
                 string.Copy(fst_chain->ChainID());
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ptnr1_label_seq_id")) {
                 if (fst_chain->chain_type() == ATOMP_TOKEN ||
                     fst_chain->chain_type() == ATOMN_TOKEN)
                      string.Copy(Fst->Field[2]);
                 else string.Copy(".");
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_ptnr1_label_ins_code")) {
                 string.Copy(Fst->InsCode);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ptnr1_label_atom_id")) {
                 string.Copy(fst_atom);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_ptnr1_label_alt_loc")) {
                 string.Copy(fst_loc);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ptnr1_symmetry")) {
                 if (strcmp(sym_op1, ""))
                      string.Copy(sym_op1);
                 else string.Copy("1_555");
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_ptnr1_standard_comp_id")) {
                 string.Copy(standard_id);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr2_label_comp_id")) {
                 if (Snd) string.Copy(Snd->Field[0]);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr2_label_asym_id")) {
                 if (snd_chain) string.Copy(snd_chain->ChainID());
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr2_label_seq_id")) {
                 if (Snd) {
                      if (snd_chain->chain_type() == ATOMP_TOKEN ||
                          snd_chain->chain_type() == ATOMN_TOKEN)
                           string.Copy(Snd->Field[2]);
                      else string.Copy(".");
                 }
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ndb_ptnr2_label_ins_code")) {
                 if (Snd) string.Copy(Snd->InsCode);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ptnr2_label_atom_id")) {
                 string.Copy(snd_atom);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ndb_ptnr2_label_alt_loc")) {
                 string.Copy(snd_loc);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                       "ptnr2_symmetry")) {
                 if (strcmp(sym_op2, ""))
                      string.Copy(sym_op2);
                 else string.Copy("1_555");
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr1_auth_comp_id")) {
                 string.Copy(Fst->Field[3]);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr1_auth_asym_id")) {
                 string.Copy(fst_chain->PDB_ChainID());
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr1_auth_seq_id")) {
                 if (strcmp(Fst->InsCode, "")) {
                      sprintf(value, "%s%s", Fst->Field[4], Fst->InsCode);
                      string.Copy(value);
                 } else string.Copy(Fst->Field[4]);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr2_auth_comp_id")) {
                 if (Snd) string.Copy(Snd->Field[3]);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr2_auth_asym_id")) {
                 if (snd_chain) string.Copy(snd_chain->PDB_ChainID());
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ptnr2_auth_seq_id")) {
                 if (Snd) {
                      if (strcmp(Snd->InsCode, "")) {
                           sprintf(value, "%s%s", Snd->Field[4], Snd->InsCode);
                           string.Copy(value);
                      } else string.Copy(Snd->Field[4]);
                 }
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ndb_ptnr3_label_atom_id")) {
                 string.Copy(trd_atom);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ndb_ptnr3_label_seq_id")) {
                 if (Trd) string.Copy(Trd->Field[2]);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ndb_ptnr3_label_asym_id")) {
                 if (trd_chain) string.Copy(trd_chain->ChainID());
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ndb_ptnr3_label_alt_loc")) {
                 string.Copy(trd_loc);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "ndb_ptnr3_label_ins_code")) {
                 if (Trd) string.Copy(Trd->InsCode);
            } else if (!strcasecmp(CifCategory[id].keywords[l].name,
                      "details")) {
                 if (comment) string.Copy(comment);
            }
            Table->UpdateCell(string, l, nrow);
       }
       nrow++;
       return 1;
}

static int pdb_rev_compare(const void *a, const void *b)
{
       return (((PDB_REV *) a)->num - ((PDB_REV *) b)->num);
}

void _MAXIT::cif_layer1_to_layer2_revdat()
{
       int i, database_id, database_code, rowNo;
       char PDB_ID[10], value[20];
       CifString cifstring;
       ISTable *Table = NULL, *Table1 = NULL, *tmpTable = NULL;
       CIF_CATEGORY *cifcategory = NULL;

       Table = _CifObj->GetTablePtr(_StructureId, "database_PDB_rev");
       if (Table == NULL) {
            cifcategory = find_category("database_PDB_rev");
            Table = create_new_table(cifcategory);
            _CifObj->WriteTable(Table, _StructureId, "database_PDB_rev");
       }
       Table1 = _CifObj->GetTablePtr(_StructureId, "database_PDB_rev_record");
       if (Table1 == NULL) {
            cifcategory = find_category("database_PDB_rev_record");
            Table1 = create_new_table(cifcategory);
            _CifObj->WriteTable(Table1, _StructureId, "database_PDB_rev_record");
       }
 
       strcpy(PDB_ID, "");
       tmpTable = _CifObj->GetTablePtr(_StructureId, "database_2");
       if (!is_empty_table(tmpTable)) {
            database_id = tmpTable->GetColumnIndex("database_id");
            database_code = tmpTable->GetColumnIndex("database_code");
            rowNo = tmpTable->GetNumRows();
            for (i = 0; i < rowNo; i++) {
                 get_value(cifstring, tmpTable, database_id, i);
                 if (cifstring == "PDB") {
                      get_value(cifstring, tmpTable, database_code, i);
                      strcpy(PDB_ID, cifstring.Text());
                      break;
                 }
            }
       }
       int num = Table->GetNumRows();
       int num_index = Table->GetColumnIndex("num");
       int date_index = Table->GetColumnIndex("date");
       int replaces_index = Table->GetColumnIndex("replaces");
       int type_index = Table->GetColumnIndex("mod_type");
       Table->AddRow();
       sprintf(value, "%d", num+1);
       cifstring.Copy(value);
       Table->UpdateCell(cifstring, num_index, num);
       cifstring.Copy("2000-01-12");
       Table->UpdateCell(cifstring, date_index, num);
       cifstring.Copy(PDB_ID);
       Table->UpdateCell(cifstring, replaces_index, num);
       cifstring.Copy("4");
       Table->UpdateCell(cifstring, type_index, num);

       char changes[7][8] = { "HEADER", "COMPND", "REMARK", "JRNL", "ATOM",
                              "SOURCE", "SEQRES" };
       int irow = Table1->GetNumRows();
       num_index = Table1->GetColumnIndex("rev_num");
       type_index = Table1->GetColumnIndex("type");
       for (i = 0; i < 7; i++) {
            Table1->AddRow();
            sprintf(value, "%d", num+1);
            cifstring.Copy(value);
            Table1->UpdateCell(cifstring, num_index, irow);
            cifstring.Copy(changes[i]);
            Table1->UpdateCell(cifstring, type_index, irow);
            irow++;
       }

       Table = _CifObj->GetTablePtr(_StructureId, "ndb_database_status");
       if (is_empty_table(Table)) return;
       int status_code = Table->GetColumnIndex("status_code");
       if (status_code < 0) return;
       get_value(cifstring, Table, status_code, 0);
       if (cifstring == "" || !strcasecmp(cifstring.Text() , "PROC")) {
            cifstring.Copy("REL");
            Table->UpdateCell(cifstring, status_code, 0);
       }
}
