
#include <vector>
#include <iostream>
#include "PTree.h"
#include "Sequence.h"
using namespace std;

PTree::PTree(const vector<Sequence *> & leaves)
{
    int num_leaves = leaves.size();
    if (num_leaves & (num_leaves - 1))
    {
        cerr << "Ptree::Ptree(): Number of initializing leaves is not a power of 2!!" << endl;
    }
    else
    {
        vector<Sequence> * my_leaves = new vector<Sequence>(num_leaves);
        for (int i = 0; i < num_leaves; i++)
        {
            (*my_leaves)[i] = *leaves[i];
        }
        myLevels.push_back(my_leaves);
        for (int level_index = 1, level_size = num_leaves / 2;
             level_size;
             level_index++, level_size /= 2)
        {
            vector<Sequence> * level = new vector<Sequence>(level_size);
            for (int i = 0; i < level_size; i++)
            {
                (*level)[i] =
                    (*myLevels[level_index-1])[2*i].parent(
                        (*myLevels[level_index-1])[2*i+1]
                    );
            }
            myLevels.push_back(level);
        }
    }
}

PTree::~PTree()
{
    for (int i = 0, sz = myLevels.size(); i < sz; i++)
    {
        delete myLevels[i];
    }
}

void PTree::print(ostream & out, int level, int index,
    string prefix, string subprefix) const
{
    out << prefix;
    out << myLevels[level][0][index];
    out << endl;
    if (level > 0)
    {
        print(out, level - 1, index * 2, subprefix + "+-", subprefix + "| ");
        print(out, level - 1, index * 2 + 1, subprefix + "`-", subprefix + "  ");
    }
}

ostream & operator<<(ostream & out, const PTree & p)
{
    p.print(out, p.myLevels.size() - 1, 0, "", "");
    return out;
}

int PTree::getCount()
{
    int count = 0;
    for (int i = 0, levels = myLevels.size(); i < levels; i++)
    {
        for (int j = 0, l_size = myLevels[i][0].size(); j < l_size; j++)
        {
            count += myLevels[i][0][j].getCount();
        }
    }
    return count;
}

void PTree::label()
{
    for (int i = 0, levels = myLevels.size(); i < levels; i++)
    {
        for (int j = 0, l_size = myLevels[i][0].size(); j < l_size; j++)
        {
            myLevels[i][0][j].label();
        }
    }
}
