/*
 * coot-utils/secondary-structure-headers.hh
 *
 * Copyright 2017 by Medical Research Council
 * Author: Paul Emsley
 *
 * This file is part of Coot
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copies of the GNU General Public License and
 * the GNU Lesser General Public License along with this program; if not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA, 02110-1301, USA.
 * See http://www.gnu.org/licenses/
 *
 */

#ifndef SECONDARY_STRUCTURE_HEADERS_HH
#define SECONDARY_STRUCTURE_HEADERS_HH

#include <vector>
#include <string>

#include <cstdio>
#include <string.h>

#include <mmdb2/mmdb_manager.h>

namespace coot {

   class access_model : public mmdb::Model {
   public:
      explicit access_model(mmdb::Model model_in) : mmdb::Model(model_in) {}
      void add_sheets(mmdb::Sheets *sheets_in) {
         sheets.nSheets = sheets_in->nSheets;
         sheets.sheet   = sheets_in->sheet;
      }
      void add_helix(mmdb::Helix *helix) {
         // helices protected and is of type SSContainer
         if (helix) {
            helices.AddData(helix);
         }
      }
      ~access_model() {}
   };

   class secondary_structure_header_records {

   public:

      class helix_info_t {
      public:
         mmdb::Residue *start_res;
         mmdb::Residue *end_res;
         unsigned int length;
         helix_info_t(mmdb::Residue *r1, mmdb::Residue *r2, unsigned int l) : start_res(r1), end_res(r2), length(l) {}
      };

      class strand_relation_t {
      public:
         unsigned int strand_idx;
         enum sense_t { FIRST, PARALLEL, ANTI_PARALLEL, NO_RESULT };
         sense_t sense;
         strand_relation_t(unsigned int idx, sense_t s) : strand_idx(idx), sense(s) {}
         bool operator==(const strand_relation_t &sr_in) const {
            return (sr_in.strand_idx == strand_idx);
         }
         bool operator<(const strand_relation_t &sr_in) const {
            return (sr_in.strand_idx < strand_idx);
         }
         static sense_t get_strand_sense(const std::vector<mmdb::Residue *> &strand_1,
                                         const std::vector<mmdb::Residue *> &strand_2);
         static int sense_to_pdb_sense(const sense_t &s) {
            if (s == FIRST)    return 0;
            if (s == PARALLEL) return 1;
            if (s == ANTI_PARALLEL) return -1;
            return -2; // Haha.
         }
      };


   private:

      // the order of all the sheets
      std::vector<std::vector<strand_relation_t> >
      get_sheet_order(mmdb::Manager *mol,
                      mmdb::Model *model_p,
                      const std::vector<std::vector<mmdb::Residue *> > &strands_with_residues);

      void make_sheets(mmdb::Manager *mol,
                       mmdb::Model *model_p,
                       const std::vector<std::vector<mmdb::Residue *> > &strands_with_residues);

      void make_helices(mmdb::Manager *mol,
                        mmdb::Model *model_p,
                        const std::vector<helix_info_t> &helices);

      void add_secondary_structure_header_records(mmdb::Model *model_p,
               const std::vector<std::vector<mmdb::Residue *> > &helices_with_residues,
                                                  const std::vector<std::vector<mmdb::Residue *> > &strands_with_residues);

      std::string sheet_index_to_sheet_id(unsigned int idx) {
         char c = 'A';
         c += idx;
         std::string r(1,c);
         return r;
      }
      std::string helix_index_to_helix_id(int idx) {
         // old style C++
         // char buff[20];
         // std::snprintf(buff, 5, "%d", idx+1);
         // return std::string(buff);
         //
         // C++-11:
         return std::to_string(idx);
      }

   public:
      secondary_structure_header_records() {};
      secondary_structure_header_records(mmdb::Manager *mol, bool needsCalcSecStructure);
   };
}
#endif // SECONDARY_STRUCTURE_HEADERS_HH
