#ifndef _RECOMPRESSOR_H
#define _RECOMPRESSOR_H

/*******************************************************

	GUI-independent section of recompressor

*******************************************************/

#include "gui_interface.h"
#include "imagecontrol.h"
#include "rec_cb.h"
#include <avifile.h>
#include <videoencoder.h>
#include <videodecoder.h>
#include <audioencoder.h>
#include <pthread.h>

#include <string>
#include <vector>

using namespace std;

struct AudioEncoderInfo
{
    int fmt;
    int bitrate;
};

class FormatChanger
{
public:
    virtual void adjust(BITMAPINFOHEADER&) =0;
};

class Filter: public IFilterUI
{
    int counter;
public:
    Filter() : counter(1){}
    virtual ~Filter(){}
    virtual string name() =0;		//for list of all filters
    virtual string fullname() =0;  	//includes config options
    virtual CImage* process(CImage* im, int pos) =0;   //filters may affect only a part of stream
    virtual void addref()
    {
	counter++;
    }
    virtual void release()
    {
	counter--;
	if (!counter)
	    delete this;
    }
    virtual string save() =0;
    virtual void load(string) =0;
    virtual int id() const {return -1;}
};

class RecompressFilter: public Filter
{
    VideoEncoderInfo info;
    uint8_t* comp_frame;
    IVideoDecoder* vd;
    IVideoEncoder* ve;
public:
    RecompressFilter(const VideoEncoderInfo& in);
    ~RecompressFilter();
    string name() { return "Recompress filter"; }
    string fullname() { return name(); }
    CImage* process(CImage* im, int pos);
    void about(){}
    void config(){}
    string save();
    void load(string);
};

class RecKernel
{
friend class Filter;
public:
    enum KernelMode { Remove = 0, Copy, Recompress };
private:
    string strLastError;
    IRecompressCallback* _cb;
    IImageControl* _ctl;
    IAviReadFile* _rf;
    IAviWriteFile* _wf;
    RecompressFilter* _recf;
    string _fn;
    string _readfn;
    struct full_stream
    {
	IAviReadStream* stream;
	double startpos;
	double endpos;
	KernelMode mode;
    };
    vector<full_stream> v_str;
    unsigned int vs, as;
//    vector<full_stream> a_str;
    vector<Filter*> filter_list;

    vector<AudioEncoderInfo> afmt;
    vector<VideoEncoderInfo> vfmt;

public:
    RecKernel();
    ~RecKernel();
    Filter* getFilter(streamid_t id);		//creates filter registered under id
    Filter* getFilterAt(streamid_t id);		//returns filter at pos id in current list
    Filter* operator[](unsigned int);		//synonym
    unsigned int getFilterCount() const;	//size of current list
    int addFilter(Filter* fi);			//adds filter in the end of list
    int removeFilter(streamid_t id);
    int moveUpFilter(streamid_t id);
    int moveDownFilter(streamid_t id);

    int openFile(const char* fn);
    const char* getSrcFile() {return _readfn.c_str();}
    int setDestFile(const char* fn);
    const char* getDestFile() {return _fn.c_str();}


    string aboutStream(streamid_t id) const;	//first all video streams, then audio

    string lastError() const;

    bool isVideoStream(streamid_t id) const;
    bool isAudioStream(streamid_t id) const;

    AviStream::StreamType stream_type(streamid_t id) const;

//
//    int getVideoInfo(int id, VideoEncoderInfo& vi) const;
//    int getAudioInfo(int id, WAVEFORMATEX& wfmtx) const;
//
    bool isStream(streamid_t id) const;//nonzero if stream


    int setStreamMode(streamid_t id, KernelMode mode);
    int getStreamMode(streamid_t id, KernelMode& mode) const;
    int getSelection(streamid_t id, double& start, double& end) const;
    int setSelection(streamid_t id, double start, double end);
    int setSelectionStart(streamid_t id, double start);
    int setSelectionEnd(streamid_t id, double end);
    double getFrameTime(streamid_t id) const;
    double getTime(streamid_t id) const;
    void setImageControl(IImageControl* ctl);//should set size & pictures if ctl!=0 & file is opened

    string getStreamName(streamid_t id) const;
    unsigned int getStreamCount() const;
    framepos_t seek(int delta);//in frames
    //negative seeks are very slow
    framepos_t seek_pos(framepos_t pos);//seek to nearest keyframe, return its position
    framepos_t seekNextKeyFrame();
    framepos_t seekPrevKeyFrame();
    framepos_t pos() const;

    int setCompress(streamid_t id, const VideoEncoderInfo& vi);
    int setAudioCompress(streamid_t id, const AudioEncoderInfo& wf);
    int getCompress(streamid_t id, VideoEncoderInfo& vi) const;
    int getAudioCompress(streamid_t id, AudioEncoderInfo& wf) const;

    unsigned int getVideoLength() const;

    int set_callback(IRecompressCallback* rec_cb);
    int start_recompress();
    int pause_recompress();
    int stop_recompress();

    void redraw();

    int loadConfig(const char*);
    int saveConfig(const char*);
private:
    static void* RecompressThread(void* arg);

    pthread_t rec_thread;
    int rec_status;
    int pause_status;
    void _destruct();
};

#endif
