#ifndef _VIEWS_H
#define _VIEWS_H

#include "squaredance.h"

#include <locale.h>
#include <gtk/gtk.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>

#include "callbacks.h"

#define FIRST_MINORSET_SLOWDOWN				2
#define FIRST_MINORSET_STRATHSPEY_SLOWDOWN		1.5

enum display_flags {
    df_title, df_noTitle,
    df_minorSet, df_noMinorSet,
    df_showPath, df_noShowPath,
    df_debugClasp, df_noDebugClasp,
    df_frameTitle, df_noFrameTitle,
    df_showFrame, df_noShowFrame,
    df_showPerson, df_noShowPerson,
    df_showGrid, df_noShowGrid,
    df_addCounts, df_noAddCounts,
    df_addTone, df_noAddTone,
    df_openAfter, df_noOpenAfter,
    df_retainFrames, df_deleteFrames,
    df_appendFrames, df_overwriteFrames,
    df_sicilianCircle, df_noSicilianCircle,
    df_womensOrientation, df_mensOrientation,
    df_honour, df_noHonour,
    df_test, df_noTest,
    df_verbose, df_noVerbose,
    df_sicilianScale, df_noSicilianScale,
    df_png, df_noPng,
    df_svg, df_noSvg,
    df_showBar, df_noShowBar,
    df_oldProgression, df_noOldProgression
};

typedef struct timelineChunk {
    long start_time_in_44k;		/* Time from start of video as measured in audio samples, usually at 44100/sec */
    char *filename;
    struct timelineChunk *next;
    long interpolate_start, interpolate_end;	/* In input samples */
    long result_len;				/* in output samples */
    unsigned int dont_open: 1;
    unsigned int dont_close: 1;
    unsigned int save_to_buffer: 1;
    unsigned int from_buffer: 1;
    float amplify;
    int fadein_samples;			/* in output samples */
    float fadein_initial_level;
} AudioTimelineChunk;

typedef struct danceAudioTimeline {
    AudioTimelineChunk *first;
    /* The above is the list of all chunks in the stream */
    /* active is the chunk that is currently open. When active ends, the field becomes NULL and upcoming is set to active->next (unless there is no pause between in which case active is set and upcoming is not) */
    AudioTimelineChunk *active;
    AudioTimelineChunk *upcoming;
    float amplify;

    /* For the active context */
    AVFormatContext *avContext;
    AVCodecParameters *codecParams;
    AVCodec *codec;
    AVCodecContext *codecContext;
    AVStream *stream;
    AVFrame *frame;
    AVPacket *packet;
    int audioIndex;		/* The streamIndex of the audio stream in the file */
    short *translatedFrameData[2];	/* These contain all the data from the*/
	    /* current packet (which may produce several frames) as well as 3 */
	    /* samples from the last frame (so we can interpolate). They are  */
	    /* all translated to signed 16 bit samples. They are not interpolated */
	    /* We support mono and stereo. Any other channels are ignored */
    int translated_buffer_samples;
    int translated_buffer_len;
    long translated_pts, translated_next_pts;
#define INTERP_OFFSET	3	/* Copy three samples from the end of the previous frame to the start of this one */
    short endOfLastPacket[2][INTERP_OFFSET];
    unsigned int current_stereo: 1;
    unsigned int only_left_samples: 1;
    unsigned int only_right_samples: 1;
} DanceAudioTimeline;

typedef struct timeline {
    int start_frame, end_frame;		/* start_frame begins at 0. end_frame is the start_frame for the next TimeLine */
    enum timeline_type {
	tl_title,
	tl_transition_title_album,
	tl_album,
	tl_transition_album_title,
	tl_transition_title_set,
	tl_transition_title_fadeout,
	tl_honour,
	tl_scottishImproper,
	tl_stillFrames,			/* video repeats to allow for a) first call, b) music intro, c) music ending */
	tl_minorset,
	tl_transition_minor_major,
	tl_majorset
    } timeline_type;
    struct timeline *next;
} TimeLine;

typedef struct danceview {
    GtkWidget *win;
    cairo_surface_t *frame;
    cairo_t *cr;
    int width;
    int height;
    int frames_per_bar;
    int frames_per_sec;
    int title_frame_offset;
    int append_frame_offset;
    float scale;		/* pixels per dance unit */
    int xorigin, yorigin;
    float full_scale, ms_scale;
    int full_xorigin, ms_xorigin, full_yorigin, ms_yorigin;

    float usable_fraction;	/* <=1.0 FB likes to crop movies, so only put the movie in the part not cropped */
    Dance *dance;
    int couples;
    int minor_set_count;	/* How many times to run the dance */
    int initial_out_at_top;
    char *filename;		/* for movie */
    char *framedir;		/* for temporary directory for movie frames */
    BB bb;
    BB minorSetBB;
    unsigned int show_roles: 1;	/* Normally if both roles and dancers are set we want to show the dancers, but if this is set show the roles */
    unsigned int show_path: 1;
    unsigned int show_title: 1;
    unsigned int show_frameTitle: 1;	/* A small title on every page */
    unsigned int show_minorset_first: 1;
    unsigned int place_calls_underneath: 1;
    unsigned int full_place_calls_underneath: 1;
    unsigned int add_counts_to_audio: 1;
    unsigned int add_tones_to_audio: 1;
    unsigned int minorset_add_tones_to_audio: 1;	/* More accurately, add tones only in the minorset, else use music */
    unsigned int audio_output_only: 1;
    unsigned int show_bar: 1;
/* Debug bits */
    unsigned int show_frame: 1;
    unsigned int show_person: 1;
    unsigned int debugClasp: 1;
    unsigned int show_grid: 1;
    unsigned int test: 1;
/* guded */
    unsigned int titling: 1;
    unsigned int womensOrientation: 1;
    unsigned int do_honour: 1;
    float title_fadeout_frac;
    int past_path_millibars, future_path_millibars;
    cairo_pattern_t **person_patterns;
    cairo_pattern_t **edge_patterns;
    cairo_pattern_t *tripleMinorOutAtBottom[4];		/* Used for quadruple minors as well as triple, enough space here for a quintuple just in case */
    PangoLayout *layout;
    PangoLayout *call_layout;
    PangoLayout *music_layout;
    PangoLayout *title_layout;
    PangoLayout *frametitle_layout;
    PangoLayout *framefiguretitle_layout;
    PangoLayout *person_layout;
    PangoFontDescription *title_font;
    int dont_show_couples_above_me;
    int old_dont_show_couples_above_me;
    
    /* CallList *lastCall; */
    cairo_surface_t *face_surface;
    cairo_t *fcr;
    int face_size;
    unsigned int has_back_frames: 1;
    int last_back_frame_loaded;
    int dance_frame_count_of_last_back_frame;
    GdkPixbuf *back_img;
    GdkPixbuf *title_back_img;
    int back_col, fade_col, fade_delay;

    char currentMusicName[MUSICNAMELEN];
    int currentMusicFrameStart;
    CallList *currentMusicCallStart;

    FILE *audio;		/* For spoken calls */
    FILE *music;		/* For music */
    int audio_sample_rate;
    int audio_samples_out;
    int total_dance_frames;	/* Number of frames needed to display all the iterations of the dance */
    int music_end_framecnt;	/* Number of frames showing the last image of the dance as the music fades out */
    int last_frame_cnt;
    int former_frame_cnt;	/* Count of any retained frames (png output only) */
#if 0
	/* Info for adding counts to audio */
    int fc_start_slowset;
    int fc_end_slowset;
    int fc_start_normal;
    int fc_end_normal;
    int fpb_slowset;
#endif

/* stuff for libav */
    int vbit_rate;
    TimeLine *timeline;
    TimeLine *active;
    /* Audio inputs */
#define MAX_AUDIO_TIMELINES	4
#define AT_CALLS		0
#define AT_MUSIC		1
#define AT_CLAPS		2
#define AT_COUNTS		3
    /* The streams are:
      * 1. calls (also includes title, scottish honour cord, etc)
      * 2. music (if any)
      * 3. claps (if any)
      * 4. counts (if any)
      * Do we need anything else?
      * We query each stream to get the next audio level (or pair for stereo streams)
      *  then add all these together to get an output level (or pair)
     */
    unsigned int output_pngs: 1;	/* Output individual png frames and an audio.wav file to be joined by ffmpeg */
    unsigned int output_svg: 1;		/* Output an SVG video */
    unsigned int stereo_output:1 ;	/* true if the music is stereo (other's aren't) */
					/*  Non-stereo streams get added to both stereo channels on output */
    unsigned int verbose: 1;
    unsigned int shush: 1;		/* Only used by list.c */
    int original_frames_per_bar;
    DanceAudioTimeline audios[MAX_AUDIO_TIMELINES];
    short *buffered_samples;
    short *write_bpt;
    short *read_bpt;
    short *max_buf;		/* Buffer needs to be long enough for the entire minorset/body (possibly in stereo) */

    /* Output file */
    AVFormatContext *avContext;
    AVCodec *codecAudio, *codecVideo;
    AVCodecContext *codecContextAudio, *codecContextVideo;
    AVStream *avAudioStream, *avVideoStream;
    AVFrame *frameAudio, *frameVideo;
    long audio_samples_pts;

/* stuff for svg */
    FILE *svg;
    int svg_vframe;		/* These are as they are drawn. Sometimes want to display the same rendered frame twice */
    int svg_roles_used[65];
    int svg_roles_used_cnt;
    char **svg_calls_used;
    int svg_calls_used_max, svg_calls_used_cnt;
    char **svg_clasp;
    int svg_clasp_max, svg_clasp_cnt;
    struct dinfo { char *matrix; int role_index; } *svg_dancers;
    struct dinfo *svg_dancer_frames;
    int *svg_call_frames;
    char ***svg_clasp_frames;
    int svg_vframe_max;

/* Stuff for comparisons */
    char *framedirs[2];
    int biggestframe[2];
} DanceView;

    /* opennewdlg.c */
extern void gwwv_post_error(GtkWindow *owner,const char *title, const char *msg, ... );
extern int NewDlg_MakeAndRun(GtkWindow *owner);
extern int OpenDlg_MakeAndRun(GtkWindow *owner);
extern void DanceWin_LoadFile(const char *filename);
    /* dancewin.c */
extern void DanceWin_Create(Figure *figure);
    /* DanceVideo.c */
extern char *quoteCvt(char *name, int ismarkup);
extern int dancePersonWidth(DanceView *dv);
extern void danceGetCoupleColor(int coupleNum,int *edge, int *body);
extern int dancerOnTheRight( Person *p1, Person *p2);
extern void danceRender(DanceView *dv,int frame_no);
extern void danceMinorsetSlowdown(DanceView *dv);
/* extern void danceMakeVideo(Dance *dance,struct video_options *options,
	char *filename, char *framedir); */
    /* DanceComparison.c */
extern void danceMakeComparison(Comparison *comp, struct video_options *options,
	char *filename, char *framedir);
#if 0
    /* danceAudio.c */
extern void danceAudioHeader(FILE *afile);
extern void danceAddAudioTitleFile(DanceView *dv,char *audioFilename);
extern void danceAddAudioFile(DanceView *dv,char *audioFilename, int frame, double callSeconds);
extern void danceAddAudioCallFile(DanceView *dv,char *audioFilename, char *longFilename, int frame, double callSeconds);
extern void danceAddMusicFile(DanceView *dv, int frame);
extern void danceFinishAudio(DanceView *dv, int frame);
extern void danceAudioMix(DanceView *dv);
extern int danceExtraFramesForFile(DanceView *dv,char *filename,int frame, double maxSeconds);
extern void danceAudioAddCounts(DanceView *dv);
extern int danceHasClaps(Dance *dance);
extern void danceAudioAddClaps(DanceView *dv);
extern void danceAudioAppend(DanceView *dv);
#endif
    /* danceGif.c */
extern int danceOutputAnimatedGif(DanceView *dv,char *frameDir, char *outputName,Rect *crop);
    /* danceAV.c */
extern void removePngs(char *dir);
extern int  danceAVFigureFramesPerSecBar(DanceView *dv, struct video_options *options);
extern void danceAVBuildTimelines(DanceView *dv, struct video_options *options);
extern void danceABuildTimelines(DanceView *dv, struct video_options *options);
extern void danceAVStart(DanceView *dv, struct video_options *options);
extern void danceAStart(DanceView *dv, struct video_options *options);
extern void danceAVAddVideoFrame(DanceView *dv,int frame);
extern void danceAAddAudioFrames(DanceView *dv);
extern void danceAVFinish(DanceView *dv, struct video_options *options);
extern void danceFigureTitleFrames(DanceView *dv, Comparison *comp, struct video_options *options );
extern void danceAVBuildComparisonTimelines(DanceView *dv, struct video_options *options);
    /* danceSVG.c */
extern void danceMetadata(FILE *out, Figure *figure);
extern void danceSVGInit(DanceView *dv, struct video_options *options);
extern void danceSVGRenderFrame(DanceView *dv, int vframe);
extern void danceSVGWriteVideoFrame(DanceView *dv);
extern void danceSVGFinish(DanceView *dv, struct video_options *options);

#endif
