/* $Id: Spliced_exon.cpp 415574 2013-10-18 13:21:57Z chetvern $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
 *               National Center for Biotechnology Information
 *
 *  This software/database is a "United States Government Work" under the
 *  terms of the United States Copyright Act.  It was written as part of
 *  the author's official duties as a United States Government employee and
 *  thus cannot be copyrighted.  This software/database is freely available
 *  to the public for use. The National Library of Medicine and the U.S.
 *  Government have not placed any restriction on its use or reproduction.
 *
 *  Although all reasonable efforts have been taken to ensure the accuracy
 *  and reliability of the software and data, the NLM and the U.S.
 *  Government do not and cannot warrant the performance or results that
 *  may be obtained by using this software or data. The NLM and the U.S.
 *  Government disclaim all warranties, express or implied, including
 *  warranties of performance, merchantability or fitness for any particular
 *  purpose.
 *
 *  Please cite the author in any work or product based on this material.
 *
 * ===========================================================================
 *
 * Author:  .......
 *
 * File Description:
 *   .......
 *
 * Remark:
 *   This code was originally generated by application DATATOOL
 *   using the following specifications:
 *   'seqalign.asn'.
 */

// standard includes
#include <ncbi_pch.hpp>

// generated includes
#include <objects/seqalign/Spliced_exon.hpp>

// generated classes

BEGIN_NCBI_SCOPE

BEGIN_objects_SCOPE // namespace ncbi::objects::

// destructor
CSpliced_exon::~CSpliced_exon(void)
{
}


CRef<CSeq_interval>
CSpliced_exon::CreateRowSeq_interval(CSeq_align::TDim    row,
                                     const CSpliced_seg& seg) const
{
    CRef<CSeq_interval> ret;
    ret.Reset(new CSeq_interval);
    TSeqRange range = GetRowSeq_range(row, false);
    ret->SetFrom(range.GetFrom());
    ret->SetTo(range.GetTo());

    if (row == 0) {
        if ( IsSetProduct_id() ) {
            ret->SetId().Assign(GetProduct_id());
        }
        else if ( seg.IsSetProduct_id() ) {
            ret->SetId().Assign(seg.GetProduct_id());
        }
        else {
            NCBI_THROW(CSeqalignException, eInvalidAlignment,
                       "CSpliced_exon::CreateRowSeq_interval() - "
                       "missing product id.");
        }
        if ( IsSetProduct_strand() ) {
            ret->SetStrand(GetProduct_strand());
        }
        else if ( seg.IsSetProduct_strand() ) {
            ret->SetStrand(seg.GetProduct_strand());
        }
    }
    else if (row == 1) {
        // Genomic
        if ( IsSetGenomic_id() ) {
            ret->SetId().Assign(GetGenomic_id());
        }
        else if ( seg.IsSetGenomic_id() ) {
            ret->SetId().Assign(seg.GetGenomic_id());
        }
        else {
            NCBI_THROW(CSeqalignException, eInvalidAlignment, "CSpliced_exon::CreateRowSeq_interval() - "
                       "missing genomic id.");
        }
        if ( IsSetGenomic_strand() ) {
            ret->SetStrand(GetGenomic_strand());
        }
        else if ( seg.IsSetGenomic_strand() ) {
            ret->SetStrand(seg.GetGenomic_strand());
        }
    }
    return ret;
}

TSeqRange CSpliced_exon::GetRowSeq_range(CSeq_align::TDim    row,
                                         bool always_as_nuc) const
{
    if (row != 0  &&  row != 1) {
        NCBI_THROW(CSeqalignException, eInvalidRowNumber,
                   "CSpliced_exon::CreateRowSeq_interval() - "
                   "row number must be 0 or 1 for spliced-segs.");
    }
    if (row == 0) {
        _ASSERT(GetProduct_start().Which() == GetProduct_end().Which());
        switch ( GetProduct_start().Which() ) {
        case CProduct_pos::e_Nucpos:
            return TSeqRange(GetProduct_start().GetNucpos(),
                             GetProduct_end().GetNucpos());

        case CProduct_pos::e_Protpos:
            if (always_as_nuc) {
                return TSeqRange(GetProduct_start().AsSeqPos(),
                                 GetProduct_end().AsSeqPos());
            } else {
                return TSeqRange(GetProduct_start().GetProtpos().GetAmin(),
                                 GetProduct_end().GetProtpos().GetAmin());
            }

        default:
            NCBI_THROW(CSeqalignException, eInvalidAlignment,
                       "CSpliced_exon::CreateRowSeq_interval() - "
                       "start/end product-pos types do not match.");
            break;
        }
    }

        // Genomic
        return TSeqRange(GetGenomic_start(), GetGenomic_end());
}

CRangeCollection<TSeqPos> CSpliced_exon::GetRowSeq_insertions(
    CSeq_align::TDim    row, const CSpliced_seg& seg) const
{
    return GetRowSeq_insertions(row, seg,
                          CRangeCollection<TSeqPos>(TSeqRange::GetWhole()));
}

CRangeCollection<TSeqPos> CSpliced_exon::GetRowSeq_insertions(
    CSeq_align::TDim    row,
    const CSpliced_seg& seg,
    const CRangeCollection<TSeqPos> &within_product_ranges) const
{
    vector<ENa_strand> strand(2, eNa_strand_unknown);
    if (IsSetProduct_strand()) {
        strand[0] = GetProduct_strand();
    } else if (seg.IsSetProduct_strand()) {
        strand[0] = seg.GetProduct_strand();
    }
    if (IsSetGenomic_strand()) {
        strand[1] = GetGenomic_strand();
    } else if (seg.IsSetGenomic_strand()) {
        strand[1] = seg.GetGenomic_strand();
    }

    vector<int> direction;
    direction.push_back(strand[0] == eNa_strand_minus ? -1 : 1);
    direction.push_back(strand[1] == eNa_strand_minus ? -1 : 1);

    vector<TSeqPos> pos;
    pos.push_back(strand[0] == eNa_strand_minus
        ? GetRowSeq_range(0,true).GetTo() : GetRowSeq_range(0,true).GetFrom());
    pos.push_back(strand[1] == eNa_strand_minus
        ? GetRowSeq_range(1,true).GetTo() : GetRowSeq_range(1,true).GetFrom());

    CRangeCollection<TSeqPos> insertions;
    if (IsSetParts()) {
        ITERATE (TParts, it, GetParts()) {
            const CSpliced_exon_chunk& chunk = **it;
            switch (chunk.Which()) {
            case CSpliced_exon_chunk::e_Match:
                pos[0] += chunk.GetMatch() * direction[0];
                pos[1] += chunk.GetMatch() * direction[1];
                break;
    
            case CSpliced_exon_chunk::e_Mismatch:
                pos[0] += chunk.GetMismatch() * direction[0];
                pos[1] += chunk.GetMismatch() * direction[1];
                break;
    
            case CSpliced_exon_chunk::e_Diag:
                pos[0] += chunk.GetDiag() * direction[0];
                pos[1] += chunk.GetDiag() * direction[1];
                break;
    
            case CSpliced_exon_chunk::e_Product_ins:
                if (row == 0) {
                    if (strand[0] == eNa_strand_minus) {
                        insertions += TSeqRange(pos[0] - chunk.GetProduct_ins() + 1,
                                          pos[0]);
                    } else {
                        insertions += TSeqRange(pos[0],
                                          pos[0] + chunk.GetProduct_ins() - 1);
                    }
                }
                pos[0] += chunk.GetProduct_ins() * direction[0];
                break;
    
            case CSpliced_exon_chunk::e_Genomic_ins:
                /// Add genomic insertion if the current position on the product is within the range
                if (row == 1 && within_product_ranges.IntersectingWith(
                                    TSeqRange(pos[0], pos[0])))
                {
                    if (strand[1] == eNa_strand_minus) {
                        insertions += TSeqRange(pos[1] - chunk.GetGenomic_ins() + 1,
                                          pos[1]);
                    } else {
                        insertions += TSeqRange(pos[1],
                                          pos[1] + chunk.GetGenomic_ins() - 1);
                    }
                }
                pos[1] += chunk.GetGenomic_ins() * direction[1];
                break;
    
            default:
                break;
            }
        }
    }
    if (row == 0) {
        insertions &= within_product_ranges;
    }
    return insertions;
}


END_objects_SCOPE // namespace ncbi::objects::

END_NCBI_SCOPE

/* Original file checksum: lines: 57, chars: 1735, CRC32: e5745056 */
