
#   This is for all conversions EXCEPT   HVC  <--->  xyY   transforms

library( munsellinterpol )




options( width=144 )

printf <- function( msg, ... )
    {
    mess = sprintf( msg[1], ... )    # should this really be msg[1] ?
    cat( mess, '\n' )   #, file=stderr() )
    }

#   returns time in seconds, from an arbitrary origin
gettime <- function()
    {
    if( requireNamespace('microbenchmark') )
        return( microbenchmark::get_nanotime() * 1.e-9 )
    else
        return( as.double( base::Sys.time() ) )
    }




#   testing sRGB -> HVC -> sRGB
#   testing AdobeRGB -> HVC -> AdobeRGB
#   testing Lab -> HVC -> Lab
#   testing Luv -> HVC -> Luv


testMunsell <- function()
    {
    printf( "---------------------  testMunsell()  -----------------------" )

    set.seed(0)

    # make random RGBs in the cube
    count   = 1000
    RGB = matrix( runif(3*count,min=0,max=255), ncol=3 )
    rownames(RGB)   = sprintf( "%04d", 1:count )

    printf( "testing sRGB -> HVC -> sRGB with %d samples...", count )

    time_start  = gettime()
    HVC         = sRGBtoMunsell( RGB )          #; print( str(HVC) )
    RGB.back    = MunsellTosRGB( HVC )$RGB     #; print( str(RGB.back) )
    time_elapsed    = gettime() - time_start

    mask    = is.na( RGB.back[ ,1] )
    if( any( mask ) )
        {
        printf( "There were %d  sRGB -> HVC -> sRGB  failures (out of %d).", sum(mask), count )
        return(FALSE)
        }

    delta   = rowSums( abs(RGB - RGB.back) )  #; print( max(delta) )

    printf( "sRGB  max(delta)=%g   (out of %d)",  max(delta,na.rm=TRUE), sum(is.finite(delta)) )

    tol     = 3.e-2     # was 2.e-2 before v 2.3-1
    failures = sum( tol < delta ) #; print( failures )

    if( 0 < failures )
        {
        idx = which.max(delta)
        printf( "There were %d  sRGB -> HVC -> sRGB tolerance failures (out of %d).  Max error = %g > %g.",
                    failures, count, delta[idx], tol )

        df  = data.frame( row.names=1 )
        df$RGB      = RGB[idx, ,drop=FALSE]
        df$HVC      = HVC[idx, ,drop=FALSE]
        df$RGB.back = RGB.back[idx, ,drop=FALSE]
        print( df )

        return(FALSE)
        }

    printf( "sRGB passed.  %d round trips in %g sec,  %g/sample", count, time_elapsed, time_elapsed/count )


    #   test pure black
    black       = c(0,0,0)
    black.back  = as.numeric( MunsellTosRGB( sRGBtoMunsell(black) )$RGB )
    if( ! identical( black, black.back ) )
        {
        printf( "sRGB -> HVC -> sRGB .  pure black not preserved." )
        return(FALSE)
        }


    #---   AdobeRGB  -----#

    printf( "testing AdobeRGB -> HVC -> AdobeRGB with %d samples...", count )

    time_start      = gettime()
    HVC             = RGBtoMunsell( RGB, space='AdobeRGB' )         #; print( str(HVC) )
    RGB.back        = MunsellToRGB( HVC, space='AdobeRGB' )$RGB     #; print( str(RGB.back) )
    time_elapsed    = gettime() - time_start

    mask    = is.na( RGB.back[ ,1] )
    if( any( mask ) )
        {
        printf( "There were %d  AdobeRGB -> HVC -> AdobeRGB  failures (out of %d).", sum(mask), count )
        return(FALSE)
        }

    delta   = rowSums( abs(RGB - RGB.back) )  #; print( max(delta) )

    printf( "AdobeRGB  max(delta)=%g   (out of %d)",  max(delta,na.rm=TRUE), sum(is.finite(delta)) )

    tol     = 0.5
    failures = sum( tol < delta ) #; print( failures )

    if( 0 < failures )
        {
        idx = which.max(delta)
        printf( "There were %d  AdobeRGB -> HVC -> AdobeRGB tolerance failures (out of %d).  Max error = %g > %g.",
                    failures, count, delta[idx], tol )
        df  = data.frame( row.names=1 )
        df$RGB      = RGB[idx, ,drop=FALSE]
        df$HVC      = HVC[idx, ,drop=FALSE]
        df$RGB.back = RGB.back[idx, ,drop=FALSE]
        print( df )
        return(FALSE)
        }

    printf( "AdobeRGB passed.   %d round trips in %g sec,  %g/sample",
                count, time_elapsed, time_elapsed/count )




    #---   Lab   ----#
    printf( "testing Lab -> HVC -> Lab with %d samples...", count )
    Lab             = MunsellToLab( HVC )
    time_start      = gettime()
    Lab.back        = MunsellToLab( LabToMunsell( Lab ) )
    time_elapsed    = gettime() - time_start

    if( any( is.na(Lab.back) ) )
        {
        printf( "There were Lab -> HVC  failures (out of %d).", count )
        return(FALSE)
        }

    delta   = rowSums( abs(Lab - Lab.back) )

    printf( "Lab  max(delta)=%g   (out of %d)",  max(delta,na.rm=TRUE), sum(is.finite(delta)) )

    tol = 5.e-3
    failures = sum( tol < delta, na.rm=TRUE )
    if( 0 < failures )
        {
        idx = which.max(delta)
        printf(  "There were %d  Lab -> HVC -> Lab failures (out of %d).  Max error = %g",
                    failures, sum(is.finite(delta)), delta[idx] )

        df  = data.frame( row.names=1 )
        df$Lab      = Lab[idx, ,drop=FALSE]
        df$HVC      = HVC[idx, ,drop=FALSE]
        df$Lab.back = Lab.back[idx, ,drop=FALSE]
        print( df )

        return(FALSE)
        }

    printf( "Lab passed.  %d round trips in %g sec,  %g/sample", count, time_elapsed, time_elapsed/count )


    #---   Luv   ----#
    printf( "testing Luv -> HVC -> Luv with %d samples...", count )
    Luv             = MunsellToLuv( HVC )
    time_start      = gettime()
    Luv.back        = MunsellToLuv( LuvToMunsell( Luv ) )
    time_elapsed    = gettime() - time_start

    if( any( is.na(Luv.back) ) )
        {
        printf( "There were Luv -> HVC -> Luv failures (out of %d).", count )
        return(FALSE)
        }

    delta   = rowSums( abs(Luv - Luv.back) )

    printf( "Luv  max(delta)=%g   (out of %d)",  max(delta,na.rm=TRUE), sum(is.finite(delta)) )

    tol = 5.e-3
    failures = sum( tol < delta, na.rm=TRUE )
    if( 0 < failures )
        {
        idx = which.max(delta)
        printf(  "There were %d  Luv -> HVC -> Luv failures (out of %d).  Max error = %g",
                    failures, sum(is.finite(delta)), delta[idx] )

        df  = data.frame( row.names=1 )
        df$Luv      = Luv[idx, ,drop=FALSE]
        df$HVC      = HVC[idx, ,drop=FALSE]
        df$Luv.back = Luv.back[idx, ,drop=FALSE]
        print( df )

        return(FALSE)
        }

    printf( "Luv passed.  %d round trips in %g sec,  %g/sample", count, time_elapsed, time_elapsed/count )


    return( TRUE )
    }


testColorlab <- function()
    {
    printf( "---------------------  testColorlab()  -----------------------" )

    set.seed(0)
    count   = 1000

    # make random HVCs

    H   = runif( count, min=0, max=100 )
    V   = runif( count, min=0, max=10 )
    C   = runif( count, min=1, max=6 )

    HVC = cbind( H, V, C )

    # add a few some neutrals
    HVC.n   = cbind( 0, runif(20,min=0,max=10), 0 )
    HVC = rbind( HVC, HVC.n )
    HVC = rbind( HVC, c(0,0,0) )    # add pure black

    #   integers are the worst case, so make 1/2 the data integers
    idx = 1:(count/2)
    HVC[idx, ] = round( HVC[idx, ] )

    count   = nrow(HVC)
    printf( "testing HVC -> HVCH -> HVC with %d samples...", count )

    time_start    = gettime()

    HVCH        = MunsellSpecToColorlabFormat( HVC )
    HVC.back    = ColorlabFormatToMunsellSpec( HVCH )

    #   compare HVC and HVC.back
    HVC.delta   = abs(HVC - HVC.back)
    HVC.delta[ ,1]  = pmin( HVC.delta[ ,1], 100 - HVC.delta[ ,1] )
    delta = rowSums( HVC.delta )

    printf( "Colorlab max(delta) = %g.", max(delta) )

    tol = 1.e-16
    failures = sum( tol <= delta )
    if( 0 < failures )
        {
        idx = which.max( delta )
        df  = data.frame( row.names=1 )
        df$HVC      = HVC[ idx, , drop=F ]
        df$HVCH     = HVCH[ idx, , drop=F ]
        df$HVC.back = HVC.back[ idx, , drop=F ]
        printf(  "Colorlab maximum inversion error = %g.", delta[idx] )
        print( df )
        return(FALSE)
        }

    time_elapsed    = gettime() - time_start
    printf( "passed.  %d round trips in %g sec,  %g/sample", count, time_elapsed, time_elapsed/count )


    return( TRUE )
    }

x = gettime()   # load microbenchmark


if( ! testColorlab() )  stop( "testColorlab() failed !", call.=FALSE )

if( ! testMunsell() )   { stop( "testMunsell() failed !", call.=FALSE ) }



printf(  "\nPassed all Conversion tests !" )
