#include <Core/Images/TEX_FILE.h>
#include <Core/Log/LOG.h>
#include <Core/Vectors/VECTOR.h>
#include <iomanip>
using namespace PhysBAM;
template<class T> TEX_FILE<T>::
//#####################################################################
// Constructor
//#####################################################################
TEX_FILE(const std::string& filename,const RANGE<TV>& box)
    :VECTOR_IMAGE<T>(filename,box)
{
    TV size=output_box.Edge_Lengths();
    stream<<"\\documentclass[class=minimal,border=0cm]{standalone}\n";
    stream<<"\\usepackage{tikz,color}\n";
    stream<<"\\definecolor{fc}{rgb}{0,0,0}\n";
    stream<<"\\definecolor{lc}{rgb}{0,0,0}\n";
    stream<<"\\begin{document}\n";
    stream<<"\\noindent\\begin{tikzpicture}";
    unit_offset=stream.tellp();
    stream<<"                                                                                                                 \n"<<std::endl;
}
//#####################################################################
// Destructor
//#####################################################################
template<class T> TEX_FILE<T>::
~TEX_FILE()
{
    if(!stream) return;
    LOG::fprintf(stream,"\\draw[use as bounding box,draw=none](%f,%f)rectangle(%f,%f);\n",
        bounding_box.min_corner.x,bounding_box.min_corner.y,
        bounding_box.max_corner.x,bounding_box.max_corner.y);
    stream<<"\\end{tikzpicture}\n";
    stream<<"\\end{document}\n";
    stream.seekp(unit_offset,std::ios::beg);
    TV r=output_box.Edge_Lengths()/bounding_box.Edge_Lengths();
    LOG::fprintf(stream,"[x=%fpt,y=%fpt]\n\\clip(%f,%f)rectangle(%f,%f);",r.x,r.y,
        bounding_box.min_corner.x,bounding_box.min_corner.y,
        bounding_box.max_corner.x,bounding_box.max_corner.y);
    
// Emit(bounding_box.min_corner);
    // Emit(bounding_box.max_corner);
    // stream.seekp(unit_offset,std::ios::beg);
}
//#####################################################################
// Function Update_Effective_Formatting
//#####################################################################
template<class T> void TEX_FILE<T>::
Update_Effective_Formatting()
{
    if(effective_line_color!=cur_format.line_color){
        effective_line_color=cur_format.line_color;
        stream<<"\\definecolor{lc}{rgb}{"<<effective_line_color.x<<","<<effective_line_color.y<<","<<effective_line_color.z<<"}\n";}
    if(effective_fill_color!=cur_format.fill_color){
        effective_fill_color=cur_format.fill_color;
        stream<<"\\definecolor{fc}{rgb}{"<<effective_fill_color.x<<","<<effective_fill_color.y<<","<<effective_fill_color.z<<"}\n";}
}
//#####################################################################
// Function Emit_Options
//#####################################################################
template<class T> std::string TEX_FILE<T>::
String_Options()
{
    std::string str="[";
    static const char* line_style_str[4]={",none",",solid",",dotted",",dashed"};
    static const char* line_join_str[3]={",line join=miter",",line join=round",",line join=bevel"};
    if(cur_format.line_style && cur_format.line_opacity){
        str+=LOG::sprintf("line width=%f,draw=lc",
            cur_format.line_width);//,cur_format.line_join
        if(cur_format.line_join) str+=line_join_str[cur_format.line_join];
        if(cur_format.line_style>1) str+=line_style_str[cur_format.line_style];
        if(cur_format.line_opacity!=1) str+=LOG::sprintf(",draw opacity=%f",cur_format.line_opacity);
        if(cur_format.arrow_style) str+=LOG::sprintf(",arrows=%s",cur_format.arrow_style);}
    else str+="draw=none";

    if(cur_format.fill_style && cur_format.fill_opacity){
        str+=",fill=fc";
        if(cur_format.fill_opacity!=1) str+=LOG::sprintf(",fill opacity=%f",cur_format.fill_opacity);}

    if(cur_format.misc.length()>0) str+=LOG::sprintf(",%s",cur_format.misc);
    return str+"]";
}
//#####################################################################
// Function Draw_Point
//#####################################################################
template<class T> void TEX_FILE<T>::
Emit_Object(const TV &pt,T radius)
{
    if(!cur_format.line_style && !cur_format.fill_style) return;
    Update_Effective_Formatting();
    LOG::fprintf(stream,"\\draw%s(%f,%f)circle(%f);\n",
        String_Options(),pt.x,pt.y,radius);
}
//#####################################################################
// Function Draw_Line
//#####################################################################
template<class T> void TEX_FILE<T>::
Emit_Object(const TV &a,const TV &b)
{
    if(!cur_format.line_style && !cur_format.fill_style) return;
    Update_Effective_Formatting();
    LOG::fprintf(stream,"\\draw%s(%f,%f)--(%f,%f);\n",
        String_Options(),a.x,a.y,b.x,b.y);
}
//#####################################################################
// Function Draw_Line
//#####################################################################
template<class T> void TEX_FILE<T>::
Emit_Object(const TV &a,const TV &b,const TV &c)
{
    if(!cur_format.line_style && !cur_format.fill_style) return;
    Update_Effective_Formatting();
    LOG::fprintf(stream,"\\draw%s(%f,%f)--(%f,%f)--(%f,%f)--cycle;\n",
        String_Options(),a.x,a.y,b.x,b.y,c.x,c.y);
}
//#####################################################################
// Function Draw_Object
//#####################################################################
template<class T> void TEX_FILE<T>::
Emit_Object(const RANGE<TV>& box)
{
    if(!cur_format.line_style && !cur_format.fill_style) return;
    Update_Effective_Formatting();
    LOG::fprintf(stream,"\\draw%s(%f,%f) rectangle (%f,%f);\n",
        String_Options(),box.min_corner.x,box.min_corner.y,
        box.max_corner.x,box.max_corner.y);
}
//#####################################################################
// Function Emit_Object
//#####################################################################
template<class T> void TEX_FILE<T>::
Emit_Object(ARRAY_VIEW<TV> pts)
{
    if(pts.Size()<2) return;
    if(!cur_format.line_style && !cur_format.fill_style) return;
    Update_Effective_Formatting();

    LOG::fprintf(stream,"\\draw%s",String_Options());
    for(const auto&p:pts) LOG::fprintf(stream,"(%f,%f)--",p.x,p.y);
    LOG::fprintf(stream,"cycle;\n");
}
//#####################################################################
// Function Emit_Object
//#####################################################################
template<class T> void TEX_FILE<T>::
Emit_Object(ARRAY_VIEW<TV> pts,ARRAY_VIEW<ARRAY_VIEW<TV> > holes)
{
    PHYSBAM_NOT_IMPLEMENTED();
}
namespace PhysBAM{
template class TEX_FILE<float>;
template class TEX_FILE<double>;
}
