#include "waveViewWidget.h"
#include <QPainter>
#include <QPalette>
#include <QPen>
#include <QColor>
#include <QByteArray>
#include <QPaintEvent>

#include <string>
using namespace std;

const double msOneFrame = 1.0 / 4.0;

// [ms] を scale[] に従って位置情報へ変換する．
static int msToPosition(float ms, double scale)
{
    int ret;
    ret = ms * scale;
    return ret;
}

void waveViewWidget::paintEvent(QPaintEvent *e)
{
    if(pointBuffer.size() == 0) return;

    QPainter painter(this);
    // 各座標を計算する．
    int leftBlank = msToPosition(currentParameters.leftBlank, scale);
    int fixedLength = msToPosition(currentParameters.fixedLength, scale);
    int rightBlank;
    if(currentParameters.rightBlank < 0.0){
        rightBlank = leftBlank - msToPosition(currentParameters.rightBlank, scale);
    }else{
        rightBlank = msToPosition((pointBuffer.size() - 1) / msOneFrame - currentParameters.rightBlank, scale);
    }
    int preUtterance = leftBlank + msToPosition(currentParameters.preUtterance, scale);
    int voiceOverlap = leftBlank + msToPosition(currentParameters.voiceOverlap, scale);

    // 背景描画
    painter.setBrush(Qt::white);
    painter.setPen(Qt::white);
    painter.drawRect(e->rect());

    //------各パラメータ描画
    // Blanks
    painter.setBrush(Qt::lightGray);
    painter.setPen(QPen(Qt::lightGray));
    painter.drawRect(QRect(0, 0, leftBlank, this->height()));
    painter.drawRect(rightBlank, 0, this->width() - rightBlank, this->height());

    // fixedLength
    painter.setBrush(QColor(192,255,255));
    painter.setPen(QColor(192,255,255));
    painter.drawRect(leftBlank - 1 , 0, fixedLength,this->height());

    // 波形描くよ！
    painter.setPen(QPen(Qt::black));
    for(int i = e->rect().left(); i <= e->rect().right() && i < pointBuffer.size() * scale; i++){
        int index = (double)i / scale / msOneFrame;
        double maxValue = pointBuffer[index].top, minValue = pointBuffer[index].bottom;
        for(index++; index < (i+1) / scale / msOneFrame && index < pointBuffer.size(); index++){
            if(maxValue < pointBuffer[index].top){ maxValue = pointBuffer[index].top; }
            if(minValue > pointBuffer[index].bottom){ minValue = pointBuffer[index].bottom; }
        }
        int y1 = (0.5 - maxValue / 2.0) * this->height();
        int y2 = (0.5 - minValue / 2.0) * this->height();
        if(y1 == y2){
            painter.drawPoint(i,y1);
        }else{
            painter.drawLine(i,y1,i,y2);
        }
    }

    // 線描くパラメタ
    painter.setPen(Qt::blue);
    painter.drawLine(preUtterance,0,preUtterance,this->height());

    painter.setPen(Qt::red);
    painter.drawLine(voiceOverlap, 0, voiceOverlap, this->height());
}



void waveViewWidget::setScaleChange(double scale)
{
    if(scale > 0.0){
        this->scale = scale;
        this->resize((int)(pointBuffer.size() * msOneFrame * scale), this->height());
        if(parent){
            parent->resize(this->width(), parent->height());
        }
        this->update();
    }
}

bool waveViewWidget::readWaveFile(QString fileName)
{
    string s;

    QByteArray byteArray = fileName.toLocal8Bit();
    s = byteArray.data();
    return (wave.readWaveFile(s) == 1);
}

void waveViewWidget::setBuffer()
{
    double samplesInFrame = (double)wave.getSamplesInSec() * msOneFrame / 1000.0;
    int    bufferSize;
    vector<double> waveBuffer;

    wave.getWaveBuffer(waveBuffer);
    bufferSize = (double)waveBuffer.size() / samplesInFrame;
    pointBuffer.resize(bufferSize);

    double totalMaxAbs = 1.0e-10;
    for(int i = 0; i < bufferSize; i++){
        double minValue = 1.0, maxValue = -1.0;
        int index = (double)i * samplesInFrame;
        for(int j = index; j < index + samplesInFrame && j < waveBuffer.size(); j++){
            if(waveBuffer[j] < minValue){minValue = waveBuffer[j];}
            if(waveBuffer[j] > maxValue){maxValue = waveBuffer[j];}
            if(totalMaxAbs < fabs(minValue)){
                totalMaxAbs = fabs(minValue);
            }
            if(totalMaxAbs < fabs(maxValue)){
                totalMaxAbs = fabs(maxValue);
            }
        }
        this->pointBuffer[i].top = maxValue;
        this->pointBuffer[i].bottom = minValue;
    }
    for(int i = 0; i < bufferSize; i++){
        pointBuffer[i].top /= totalMaxAbs;
        pointBuffer[i].bottom /= totalMaxAbs;
    }
    this->setUpdatesEnabled(false);
    this->parent->resize((int)(pointBuffer.size() * scale * msOneFrame), parent->height());
    this->resize((int)(pointBuffer.size() * scale * msOneFrame), this->height());
    this->setUpdatesEnabled(true);
}

void waveViewWidget::setWaveBuffer(double *buffer, int length)
{
    if(!buffer || length <= 0){ return; }
    wave.setWaveBuffer(buffer, length);
    setBuffer();
    update();
}

void waveViewWidget::setUtauParameters(QUtauParameters *p)
{
    // ファイル名が一致しない場合は読み込みを行う．
    if(QString::compare(p->fileName, this->currentParameters.fileName) != 0){
        // 読み込み処理
        qDebug("---begin reading waveFile.");
        if(!this->readWaveFile(p->fileName)){
            // 読み込み失敗時の処理
            // this->destroyWave();
            qDebug("can't read the file!");
            return;
        }
        this->setBuffer();
    }else if(QString::compare(p->alias, this->currentParameters.alias) == 0){
        // ファイル名もエイリアスも一致した場合は何もしなくてよい．
        return;
    }
    // ファイルが読み込めたのでパラメタを転写．
    this->currentParameters = *p;
    this->update();
    qDebug("succeeded.");
}


waveViewWidget::waveViewWidget(QWidget *parent) :
    QWidget(parent)
{
    this->parent = parent;
    this->scale = 1.0;
}
