/*
 *  TnGmColorBytes.hpp
 *  TnGeoMath
 *
 *  Created by thant on 3/10/2011.
 *  Copyright 2011 TeleNav Inc. All rights reserved.
 *
 */

#ifndef TN_GM_COLOR_BYTES_INCLUDED
#define TN_GM_COLOR_BYTES_INCLUDED

#include <assert.h>

#include <foundation/Math/misc.hpp>
#include <foundation/Math/Array2.hpp>

namespace Tn {
    
namespace math {
        

template <int I>
struct ColorBytes
{
    static int const component_count = I;

    ColorBytes() {}     // doesn't initialze

    ColorBytes(ColorBytes<I> const & that) {pe<I-1,uint8_t>::copy(c,that.c);}

    ColorBytes<I> & operator=(ColorBytes<I> const & that) {
        pe<I-1,uint8_t>::copy(c,that.c);
        return *this;
    }

    void zero() {pe<I-1,uint8_t>::zero(c);}

    uint8_t & operator[](int i) {
        assert((i<I) && (i>=0));
        return c[i];
    }

    uint8_t const & operator[](int i) const {
        assert((i<I) && (i>=0));
        return c[i];
    }

    uint8_t c[I];
};


template <int I>
ColorBytes<I> blend(ColorBytes<I> const & a,
                    ColorBytes<I> const & b,
                    ColorBytes<I> const & c,
                    ColorBytes<I> const & d)
{
    ColorBytes<I> result;

    // The compiler should unwrap this. The 0x2 is to avoid biasing downwards.
    for (int i=0; i<I; ++i) {
        result.c[i] = (uint8_t)((a[i] + b[i] + c[i] + d[i] + 0x2) >> 2);
    }
    return result;
}



template <int I>
typename Array2<ColorBytes<I> >::ptr mip(typename Array2<ColorBytes<I> >::ptr const & source) {

    if (!source) return source; // empty pointer

    int oxs = source->getWidth();
    int oys = source->getHeight();

    assert((oxs>0) && (oys>0));

    int nxs = (oxs==1)?1:(oxs/2);
    int nys = (oys==1)?1:(oys/2);

    typename Array2<ColorBytes<I> >::ptr dest = typename Array2<ColorBytes<I> >::ptr(new Array2<ColorBytes<I> >(nxs, nys));

    Array2<ColorBytes<I> > const & ora = *source;
    Array2<ColorBytes<I> > & nra = *dest;

    int next_i = (nxs==1)?0:1;
    int next_j = (nys==1)?0:1;

    for (int j=0; j<nys; ++j) {
      for (int i=0; i<nxs; ++i) {

          int j2 = j*2;
          int i2 = i*2;

          nra[j][i] = blend(ora[j2         ][i2         ],
                            ora[j2         ][i2 + next_i],
                            ora[j2 + next_j][i2         ],
                            ora[j2 + next_j][i2 + next_i]);
      }
    }

    return dest;
}

} // namespace math
    
} // namespace Tn

#endif
