# pragma once
# include "ParseArgs.h"
# include "basedata.h"
# include "mdatetime.h"
# include "mregex.h"
# include "traits.h"
# include "uvdata.h"
using michlib : : MDateTime ;
# if defined GENACTIONLIST
# define ADD_ACTION(actclass, actname, suptest, ...) ADD ACTION CLASS: actclass
# else
# define ADD_ACTION(actclass, actname, suptest, ...) \
class Action # # actclass __VA_OPT__ ( : public ) __VA_ARGS__ \
{ \
public : \
static constexpr const char * name = # actname ; \
template < class Source > static constexpr bool IsSupported = ( suptest ) ; \
template < class Source > static MString DoAction ( const CLArgs & args , Source & data ) ; \
} ;
# endif
template < class D > size_t GetTIndex ( const D & data , const MDateTime & t )
{
size_t nt = data . NTimes ( ) ;
if ( t < = data . Time ( 0 ) ) return 0 ;
if ( t > = data . Time ( nt - 1 ) ) return nt - 1 ;
for ( size_t i = 0 ; i < nt - 1 ; i + + )
if ( t > = data . Time ( i ) & & t < = data . Time ( i + 1 ) ) return ( t - data . Time ( i ) < = data . Time ( i + 1 ) - t ) ? i : ( i + 1 ) ;
return 0 ;
}
template < class D > std : : pair < TIndex , MString > GetTIndexes ( const D & data , const CLArgs & args , michlib_internal : : ParameterListEx & pars )
{
TIndex tindexes ;
if ( args . contains ( " time " ) & & ( args . contains ( " timeb " ) | | args . contains ( " timee " ) ) )
return { tindexes , " Time must be set via time parameter or timeb and timee parameter but not via both " } ;
if ( ! ( args . contains ( " time " ) | | ( args . contains ( " timeb " ) & & args . contains ( " timee " ) ) ) ) return { tindexes , " Time must be set via time parameter or timeb and timee parameter " } ;
if ( args . contains ( " time " ) )
{
MString regex = args . at ( " time " ) ;
MDateTime time ;
if ( time . FromString ( regex ) ) return { TIndex ( 1 , GetTIndex ( data , time ) ) , " " } ; // Time, not regex
if ( regex = = " BEGIN " | | regex = = " BEG " | | regex = = " FIRST " ) return { TIndex ( 1 , 0 ) , " " } ; // First time
if ( regex = = " END " | | regex = = " LAST " ) return { TIndex ( 1 , data . NTimes ( ) - 1 ) , " " } ; // Last time
michlib : : RegExpSimple reg ( regex . Buf ( ) ) ;
if ( reg . Compile ( ) ! = 0 ) return { tindexes , " Bad regular expression: " + regex } ;
for ( size_t i = 0 ; i < data . NTimes ( ) ; i + + )
{
MString date = data . Time ( i ) . ToString ( ) ;
if ( reg . Match ( date . Buf ( ) ) ) tindexes . push_back ( i ) ;
}
if ( tindexes . size ( ) = = 0 ) return { tindexes , " There are no times matching the regular expression: " + regex } ;
if ( tindexes . size ( ) = = 1 )
pars . SetParameter ( " time " , data . Time ( tindexes [ 0 ] ) . ToString ( ) ) ;
else
pars . SetParameter ( " timeregex " , args . at ( " time " ) ) ;
}
else
{
MString tb = args . at ( " timeb " ) ;
MString te = args . at ( " timee " ) ;
MDateTime b ( tb ) , e ( te ) ;
auto nt = data . NTimes ( ) ;
if ( tb = = " BEGIN " | | tb = = " BEG " ) b = data . Time ( 0 ) ;
if ( te = = " LAST " | | te = = " END " ) e = data . Time ( nt - 1 ) ;
const MDateTime & beg = ( b < e ) ? b : e ;
const MDateTime & end = ( b > e ) ? b : e ;
if ( beg > data . Time ( nt - 1 ) ) return { tindexes , " Begin time " + b . ToTString ( ) + " is greater then end time in the dataset " + data . Time ( nt - 1 ) . ToTString ( ) } ;
if ( end < data . Time ( 0 ) ) return { tindexes , " End time " + e . ToTString ( ) + " is lesser then begin time in the dataset " + data . Time ( 0 ) . ToTString ( ) } ;
size_t ib = 0 , ie = nt - 1 ;
for ( size_t i = 0 ; i < nt ; i + + )
if ( data . Time ( i ) > = beg )
{
ib = i ;
break ;
}
for ( size_t i = nt ; i ! = 0 ; i - - )
if ( data . Time ( i - 1 ) < = end )
{
ie = i - 1 ;
break ;
}
tindexes . resize ( ie - ib + 1 ) ;
for ( size_t i = 0 ; i < ie - ib + 1 ; i + + ) tindexes [ i ] = i + ib ;
if ( tindexes . size ( ) = = 0 ) return { tindexes , " There are no times between " + b . ToString ( ) + " and " + e . ToString ( ) } ;
pars . SetParameter ( " timeb " , b . ToString ( ) ) ;
pars . SetParameter ( " timee " , e . ToString ( ) ) ;
}
return { tindexes , " " } ;
}
template < class D > ReadType < D > Read ( const D & data , const MString & vname , const BaseParameters * p , const TIndex & tindex )
{
using RT = ReadType < D > ;
size_t ind ;
if ( tindex . size ( ) = = 1 )
{
ind = tindex [ 0 ] ;
michlib : : message ( " Time: " + data . Time ( ind ) . ToTString ( ) ) ;
if constexpr ( ReadPSupported < D > )
return data . Read ( vname , p , ind ) ;
else if constexpr ( ReadSupported < D > )
return data . Read ( vname , ind ) ;
}
else
{
Averager < RT > out ;
bool ok = true ;
for ( size_t i = 0 ; i < tindex . size ( ) ; i + + )
{
if ( ! ok ) break ;
ind = tindex [ i ] ;
michlib : : message ( " Time: " + data . Time ( ind ) . ToTString ( ) ) ;
RT dat ;
if constexpr ( ReadPSupported < D > )
dat = data . Read ( vname , p , ind ) ;
else if constexpr ( ReadSupported < D > )
dat = data . Read ( vname , ind ) ;
if ( dat )
out . Add ( dat ) ;
else
ok = false ;
}
if ( ok ) return out . Div ( ) ;
}
return RT ( ) ;
}
template < class D > UVData < ReadType < D > > ReadUV ( const D & data , const BaseParameters * p , size_t ind )
{
using RT = ReadType < D > ;
using UV = UVData < RT > ;
michlib : : message ( " Time: " + data . Time ( ind ) . ToTString ( ) ) ;
RT u , v ;
if constexpr ( ReadPSupported < D > )
{
u = data . Read ( " u " , p , ind ) ;
v = data . Read ( " v " , p , ind ) ;
}
else if constexpr ( ReadSupported < D > )
{
u = data . Read ( " u " , ind ) ;
v = data . Read ( " v " , ind ) ;
}
return UV ( u , v ) ;
}
template < class D > UVData < ReadType < D > > ReadUV ( const D & data , const BaseParameters * p , const TIndex & tindex )
{
using RT = ReadType < D > ;
using UV = UVData < RT > ;
if ( tindex . size ( ) = = 1 )
return ReadUV ( data , p , tindex [ 0 ] ) ;
else
{
Averager < UV > out ;
bool ok = true ;
size_t ind ;
for ( size_t i = 0 ; i < tindex . size ( ) ; i + + )
{
if ( ! ok ) break ;
ind = tindex [ i ] ;
michlib : : message ( " Time: " + data . Time ( ind ) . ToTString ( ) ) ;
RT u , v ;
if constexpr ( ReadPSupported < D > )
{
u = data . Read ( " u " , p , ind ) ;
v = data . Read ( " v " , p , ind ) ;
}
else if constexpr ( ReadSupported < D > )
{
u = data . Read ( " u " , ind ) ;
v = data . Read ( " v " , ind ) ;
}
UV dat ( u , v ) ;
if ( dat )
out . Add ( dat ) ;
else
ok = false ;
}
if ( ok ) return out . Div ( ) ;
}
return UV ( ) ;
}
template < class D > std : : pair < struct Region , MString > GetRegion ( const CLArgs & args )
{
struct Region reg ;
if constexpr ( ! ParametersRequiredRegion < D > ) return { reg , " " } ;
if ( ! ( args . contains ( " lonb " ) & & args . contains ( " lone " ) & & args . contains ( " latb " ) & & args . contains ( " late " ) ) ) return { reg , " Region not specified (lonb, lone, latb, late) " } ;
reg . lonb = args . at ( " lonb " ) . ToReal ( ) ;
reg . lone = args . at ( " lone " ) . ToReal ( ) ;
real latb = args . at ( " latb " ) . ToReal ( ) ;
real late = args . at ( " late " ) . ToReal ( ) ;
reg . latb = std : : min ( latb , late ) ;
reg . late = std : : max ( latb , late ) ;
return { reg , " " } ;
}