/*
 * Tools related to the MitoPacq, the CBIA time-lapse cell observation simulator.
 *
 * Copyright (C) 2005-2013   Centre for Biomedical Image Analysis (CBIA)
 *
 * This library-related tools is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <i3d/image3d.h>

using namespace std;
using namespace i3d;

template <class VOXEL> void DoRotate(Image3d <VOXEL> &Input, Image3d <VOXEL> &Output, char axe)
{
    i3d::Resolution res = Input.GetResolution();

    size_t x, y, z;
    switch (axe)
    {
    case 'x':
    case 'X':
        Output.MakeRoom(Input.GetSizeX(), Input.GetSizeZ(), Input.GetSizeY());
        Output.SetResolution( i3d::Resolution(res.GetX(),res.GetZ(),res.GetY()) );
	Output.SetOffset( i3d::Offset(0.,0.,0.) );

        for (z = 0; z < Input.GetSizeZ(); ++z)
            for (y = 0; y < Input.GetSizeY(); ++y)
                for (x = 0; x < Input.GetSizeX(); ++x)
                {
                    Output.SetVoxel(x, z, y, Input.GetVoxel(x, y, z));
                }
        break;
    case 'y':
    case 'Y':
        Output.MakeRoom(Input.GetSizeZ(), Input.GetSizeY(), Input.GetSizeX());
        Output.SetResolution( i3d::Resolution(res.GetZ(),res.GetY(),res.GetX()) );
	Output.SetOffset( i3d::Offset(0.,0.,0.) );
        for (z = 0; z < Input.GetSizeZ(); ++z)
            for (y = 0; y < Input.GetSizeY(); ++y)
                for (x = 0; x < Input.GetSizeX(); ++x)
                {
                    Output.SetVoxel(z, y, x, Input.GetVoxel(x, y, z));
                }
        break;
    case 'z':
    case 'Z':
        Output.MakeRoom(Input.GetSizeY(), Input.GetSizeX(), Input.GetSizeZ());
        Output.SetResolution( i3d::Resolution(res.GetY(),res.GetX(),res.GetZ()) );
	Output.SetOffset( i3d::Offset(0.,0.,0.) );
        for (z = 0; z < Input.GetSizeZ(); ++z)
            for (y = 0; y < Input.GetSizeY(); ++y)
                for (x = 0; x < Input.GetSizeX(); ++x)
                {
                    Output.SetVoxel(y, x, z, Input.GetVoxel(x, y, z));
                }
        break;
    }
}


int main(int argc, char **argv)
{
    cout << argv[0] << " - part of the tools set of the OpticalFlow library \n"
         "Copyright (C) 2005-2013 Centre for Biomedical Image Analysis (CBIA)\n"
         "This is free software; see the source for copying conditions. "
         "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR "
         "A PARTICULAR PURPOSE.\n\n";

    if (argc < 4)
    {
        cout << "Bad number of parameters\nUsage: " << argv[0] << " input output around_axe\nexample: " << argv[0] << " input.tif output.tif x\n";
        return -2;
    }
    try
    {
        cerr << "Reading image Type" << endl;
        ImgVoxelType vt = ReadImageType(argv[1]);
        cerr << "Voxel=" << VoxelTypeToString(vt) << endl;

        switch (vt)
        {
        case Gray8Voxel:
            {
                Image3d <GRAY8> Input(argv[1]);
                Image3d <GRAY8> Output;
                DoRotate(Input, Output, argv[3][0]);
                Output.SaveImage(argv[2]);
                break;
            }
        case FloatVoxel:
            {
                Image3d <float> Input(argv[1]);
                Image3d <float> Output;
                DoRotate(Input, Output, argv[3][0]);
                Output.SaveImage(argv[2]);
                break;
            }
        default:
            cerr << "Other voxel types not supported" << endl;
        }
    }
    catch(IOException & e)
    {
        cerr << e << endl;
        exit(1);
    }
    catch(InternalException & e)
    {
        cerr << e << endl;
        exit(1);
    }
    catch(bad_alloc &)
    {
        cerr << "Not enough memory." << endl;
        exit(1);
    }
    catch(...)
    {
        cerr << argv[0] << "Unknown exception." << endl;
        exit(1);
    }
    return 0;
}
