//#####################################################################
// Copyright 2020.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################

#include <Core/Arrays/ARRAY.h>
#include <Core/Log/LOG.h>
#include <Core/Vectors/VECTOR.h>

using namespace PhysBAM;

// TASK 1: read through VECTOR.h, VECTOR_3D.h, VECTOR_2D.h, VECTOR_1D.h, and
// VECTOR_0D.h.  Mostly at this stage get a general idea of what functions are
// available.

int TASK=-1;

template<class A>
void Test(const A& a,const std::string& sol)
{
    if(TASK>=0) std::cout<<"TASK: "<<TASK<<std::endl;
    std::cout<<"should be: "<<sol<<std::endl;
    std::cout<<"computed : "<<a<<std::endl;
    if(LOG::sprintf("%P",a)==sol) std::cout<<"SAME\n"<<std::endl;
    else std::cout<<"DIFFERENT\n"<<std::endl;
    TASK=-1;
}

int main(int argc, char* argv[])
{
    // These are typical PhysBAM typedefs.  You will see T and TV everywhere.
    typedef double T;
    typedef VECTOR<T,3> TV;

    // Note that vectors initialize automatically to zero.
    Test(TV(),"(0 0 0)");
    Test(TV(1.1,3,0),"(1.1 3 0)");
    T s=0;
    TV w;
    VECTOR<T,4> w4;
    int k=0;
    
    TV u(1.2,3.4,-1.2);
    TV v(0.4,.3,0);

    TASK=2;
    // Compute the magnitude s of v, and replace v with the unit vector in the
    // same direction.  (There is a routine for this.)
    // TODO
    Test(v,"(0.8 0.6 0)");
    Test(s,"0.5");

    TASK=3;
    // Compute the dot product of u and v.
    // TODO
    Test(s,"3");

    TASK=4;
    w=TV(12,15,16);
    // Let w = u*4 + (w/|w|)*5.  One statement only.
    // TODO
    Test(w,"(7.2 16.6 -1.6)");

    TASK=5;
    // Compute the magnitude of vector v.
    // TODO
    Test(s,"1");

    TASK=6;
    // Compute the square of the magnitude of vector u.
    // TODO
    Test(s,"14.44");

    TASK=7;
    // Compute the minimum element of vector u.
    // TODO
    Test(s,"-1.2");

    TASK=8;
    // Compute the maximum element of vector u.
    // TODO
    Test(s,"3.4");

    TASK=9;
    // Compute the sum of the elements in vector u.
    // TODO
    Test(s,"3.4");

    TASK=10;
    // Set the second element of u to be 2.
    // TODO
    Test(u,"(1.2 2 -1.2)");

    TASK=11;
    // Set u to its new value.
    // TODO
    Test(u,"(1 2 10)");

    TASK=12;
    // Set v to its new value.
    // TODO
    Test(v,"(9 1 0)");

    TASK=13;
    // For the tests that follow, compute w by combining u and v and using other
    // operations.  Don't set w to the correct values by setting them directly.
    // TODO
    Test(w,"(10 3 10)");

    // TODO
    Test(w,"(-26 -1 10)");

    // TODO
    Test(w,"(4 8 40)");

    // Hint: this can be computed by calling a single operator.
    // TODO
    Test(w,"(1 4 100)");

    // TODO
    Test(w,"(9 0.5 0)");

    // TODO
    Test(w,"(4 -4.5 -5)");

    TASK=14;
    // Append 3 to v.  Note that the result will be a different type.
    // TODO
    Test(w4,"(9 1 0 3)");

    TASK=15;
    // Compute the cross product of v and u.
    // TODO
    Test(w,"(10 -90 17)");

    TASK=16;
    // Calculate a nonzero vector w such that the dot product of u and w is zero.
    // TODO
    Test(w.Magnitude()>0,"1");
    Test(w.Dot(u),"0");

    TASK=17;
    // Sort the elements in w4.
    // TODO
    Test(w4,"(0 1 3 9)");

    TASK=18;
    // Reverse the order of elements in w4.
    // TODO
    Test(w4,"(9 3 1 0)");

    TASK=19;
    // Use a loop to set u.  The size of a vector can be obtained via m or
    // Size(), just as for ARRAY.  Note that now the m is a compile-time
    // constant.
    // TODO
    Test(u,"(1 3 5)");

    TASK=20;
    // Use a range-based for loop to set u.
    // TODO
    Test(u,"(1 9 25)");

    TASK=21;
    // Find the index of the entry of u that is 9.  (What happens if the item
    // being searched for is not found?)
    // TODO
    Test(u(k),"9");

    return 0;
}
