//-----------------------------------------------------------------------------
// NastOutputContextIDL.cpp
//-----------------------------------------------------------------------------
//
//  Copyright (C) 1998 Technische Universitaet Muenchen, Germany
//  written by Bernhard Brueck
//
//  This file is part of Nast++
//
//-----------------------------------------------------------------------------
//  Files fuer IDL rausschreiben
//-----------------------------------------------------------------------------
//  Changes:
//

#include "NastOutputContextIDL.h"
#include "NastDebug.h"
#include "NastGrid2d.h"
#include "NastStaggeredGrid2d.h"

#include <string.h>

#ifndef _MSC_VER
#    include <unistd.h>
#endif

//-----------------------------------------------------------------------------
//                    Konstruktor + Destruktor
//-----------------------------------------------------------------------------

//  Defaultconstr.
CNastOutputContextIDL::CNastOutputContextIDL( const char *szFilename )
    : m_fhGrid(0),
      m_fhGridU(0),
      m_fhGridV(0),
      m_fhGridP(0)
{
    NAST_ASSERT( szFilename );

    m_szFilename = new char[strlen(szFilename)+1];
    m_szFilename = strcpy( m_szFilename, szFilename );
}

//  Destruktor
CNastOutputContextIDL::~CNastOutputContextIDL()
{
    if( m_fhGrid  ) 
    {
        fclose( m_fhGrid );
        m_fhGrid = 0;
    }
    if( m_fhGridU ) 
    {
        fclose( m_fhGridU );
        m_fhGrid = 0;
    }

    if( m_fhGridV ) 
    {
        fclose( m_fhGridV );
        m_fhGrid = 0;
    }

    if( m_fhGridP ) 
    {
        fclose( m_fhGridP );
        m_fhGrid = 0;
    }
 
    m_fhGrid = 0;
    m_fhGridU = 0;
    m_fhGridV = 0;
    m_fhGridP = 0;
    
    delete m_szFilename;
    m_szFilename = 0;
}

//-------------------------------------------------------------------------
//                              Hilfsfunktionen
//-------------------------------------------------------------------------

// liefert einen Zeiger auf einen String an dem szAppend angehaengt wurde
static  char* 
append( const char *szString, const char* szAppend )
{
    static char szTmp[1024]="";	

    szTmp[0]= 0;
    strcpy( szTmp, szString );
    strcat( szTmp, szAppend );

    return szTmp;
}

//  erzeugt einen Stream und schreibt die noetigen Headerdaten 
FILE* 
CNastOutputContextIDL::createStream( const char *szName, 
        			     const CNastGrid2d &grid )
{
    NAST_ASSERT( szName );
    FILE *fh = fopen( szName, "w" );
    if( fh == 0)
        NAST_FATAL_ERROR("Fehler beim erzeugen des Files");

    fprintf( fh, "%f\n", grid.box().sizeX());
    fprintf( fh, "%f\n", grid.box().sizeY());
    fprintf( fh, "%d\n", grid.sizeI());
    fprintf( fh, "%d\n", grid.sizeJ());

    return fh;
}

//-------------------------------------------------------------------------
//                              Memberfunktionen
//-------------------------------------------------------------------------

void 
CNastOutputContextIDL::out( const CNastStaggeredGrid2d &grid )
{
    NAST_ASSERT_VALID( this );

    CNastGrid2d gridP( grid.box(),
        	       grid.sizeI(),
        	       grid.sizeJ());

    CNastGrid2d gridU( grid.box(),
        	       grid.sizeI(),
        	       grid.sizeJ());

    CNastGrid2d gridV( grid.box(),
        	       grid.sizeI(),
        	       grid.sizeJ());

    if( m_fhGridU == 0) // noch keine streams fuer StaggeredGrid vorhanden ?
    {
        char *szName;

        szName = append( m_szFilename, ".U.out");
        m_fhGridU = createStream( szName, gridU);

        szName = append( m_szFilename, ".V.out");
        m_fhGridV = createStream( szName, gridV);

        szName = append( m_szFilename, ".P.out");
        m_fhGridP = createStream( szName, gridP );
    }

    // die Geschwindigkeiten interpolieren
    for( int i = 0; i < grid.sizeI(); i++)
        for( int j = 0; j < grid.sizeJ(); j++)
        {
            if( grid.cell(i,j).isFluid())
            {
        	// die Mittelpunkte der Zellen (anhand vom Druckgitter)
        	CNastPoint2d pntMid = grid.gridP().pos(i+1,j+1);
        	
        	// die Werte an diesen Punkten erfragen
        	CNastVector2d vel = grid.velocity( pntMid );
        	
        	gridU(i,j) = vel.x();
        	gridV(i,j) = vel.y();
        	gridP(i,j) = grid.pressure(pntMid);
            }
        }

    writeData( m_fhGridU, gridU );
    writeData( m_fhGridV, gridV );
    writeData( m_fhGridP, gridP );
}

void 
CNastOutputContextIDL::out( const CNastGrid2d &grid )
{
    NAST_ASSERT_VALID( this );

    if( m_fhGrid == 0 )	// passender Stream noch nicht vorhanden ?
    {
        //  dann muss er erzeugt werden
        char *szName = append(m_szFilename,".out");
        m_fhGrid = createStream( szName, grid );
    }

    //  Ausgabe des Gitteres in den stream
    writeData( m_fhGrid, grid );
}


void 
CNastOutputContextIDL::writeData( FILE *fh, const CNastGrid2d &grid )
{
    int nSize = grid.sizeI() * grid.sizeJ();
    float *tmp = new float[nSize];

    int k = 0;
    for( int j = 0; j < grid.sizeJ(); j++)
        for( int i = 0; i < grid.sizeI(); i++)
            tmp[k++] = (float)grid( i, j );

    NAST_ASSERT( k == grid.sizeI() * grid.sizeJ());
        
    fwrite( tmp, sizeof(float), nSize, fh);
    fflush( fh );

    delete [] tmp;
}

// ----------------------------------------------------------------------------
//                                    Debug
// ----------------------------------------------------------------------------

void 
CNastOutputContextIDL::debugDump( CNastDumpContext &dumpContext ) const
{
    CNastOutputContext::debugDump( dumpContext );
    dumpContext << "CNastOutputContextIDL" << "\n";
    dumpContext << "\tm_szFilename = " << m_szFilename << "\n";
    
}

void 
CNastOutputContextIDL::assertValid() const
{
    // zuerst einmal AssertValid der Basisklasse aufrufen
    CNastOutputContext::assertValid(); 
    NAST_ASSERT( m_szFilename );
}


