#include "EffectsAdvancedTest.h"

enum 
{
    kTagTextLayer = 1,

    kTagSprite1 = 1,
    kTagSprite2 = 2,

    kTagBackground = 1,
    kTagLabel = 2,
};

//------------------------------------------------------------------
//
// Effect1
//
//------------------------------------------------------------------
void Effect1::onEnter()
{
    EffectAdvanceTextLayer::onEnter();

    //auto target = getChildByTag(kTagBackground);
    
    // To reuse a grid the grid size and the grid type must be the same.
    // in this case:
    //     Lens3D is Grid3D and it's size is (15,10)
    //     Waves3D is Grid3D and it's size is (15,10)
    
    auto size = Director::getInstance()->getWinSize();
    auto lens = Lens3D::create(0.0f, Size(15,10), Vec2(size.width/2,size.height/2), 240);
    auto waves = Waves3D::create(10, Size(15,10), 18, 15);

    auto reuse = ReuseGrid::create(1);
    auto delay = DelayTime::create(8);

//    auto orbit = OrbitCamera::create(5, 1, 2, 0, 180, 0, -90);
//    auto orbit_back = orbit->reverse();

    //_bgNode->runAction( RepeatForever::create( Sequence::create( orbit, orbit_back, nullptr)  ) );
    _bgNode->runAction( Sequence::create(lens, delay, reuse, waves, nullptr) );
}

std::string Effect1::title() const
{
    return "Lens + Waves3d and OrbitCamera";
}

//------------------------------------------------------------------
//
// Effect2
//
//------------------------------------------------------------------
void Effect2::onEnter()
{
    EffectAdvanceTextLayer::onEnter();

    //auto target = getChildByTag(kTagBackground);
    
    // To reuse a grid the grid size and the grid type must be the same.
    // in this case:
    //     ShakyTiles is TiledGrid3D and it's size is (15,10)
    //     Shuffletiles is TiledGrid3D and it's size is (15,10)
    //       TurnOfftiles is TiledGrid3D and it's size is (15,10)
    auto shaky = ShakyTiles3D::create(5, Size(15,10), 4, false);
    auto shuffle = ShuffleTiles::create(0, Size(15,10), 3);
    auto turnoff = TurnOffTiles::create(0, Size(15,10), 3);
    auto turnon = turnoff->reverse();
    
    // reuse 2 times:
    //   1 for shuffle
    //   2 for turn off
    //   turnon tiles will use a new grid
    auto reuse = ReuseGrid::create(2);

    auto delay = DelayTime::create(1);
    
//    id orbit = [OrbitCamera::create:5 radius:1 deltaRadius:2 angleZ:0 deltaAngleZ:180 angleX:0 deltaAngleX:-90];
//    id orbit_back = [orbit reverse];
//
//    [target runAction: [RepeatForever::create: [Sequence actions: orbit, orbit_back, nil]]];    
    _bgNode->runAction(Sequence::create( shaky, delay, reuse, shuffle, delay->clone(), turnoff, turnon, nullptr) );
}

std::string Effect2::title() const
{
    return "ShakyTiles + ShuffleTiles + TurnOffTiles";
}


//------------------------------------------------------------------
//
// Effect3
//
//------------------------------------------------------------------
void Effect3::onEnter()
{
    EffectAdvanceTextLayer::onEnter();
    //auto bg = getChildByTag(kTagBackground);
    //auto target1 = bg->getChildByTag(kTagSprite1);
    //auto target2 = bg->getChildByTag(kTagSprite2);    
    auto waves = Waves::create(5, Size(15,10), 5, 20, true, false);
    auto shaky = Shaky3D::create(5, Size(15,10), 4, false);
    
    _target1->runAction( RepeatForever::create( waves ) );
    _target2->runAction( RepeatForever::create( shaky ) );
    
    // moving background. Testing issue #244
    auto move = MoveBy::create(3, Vec2(200,0) );
    _bgNode->runAction(RepeatForever::create( Sequence::create(move, move->reverse(), nullptr) ));    
}

std::string Effect3::title() const
{
    return "Effects on 2 sprites";
}


//------------------------------------------------------------------
//
// Effect4
//
//------------------------------------------------------------------

class Lens3DTarget : public Node
{
public:
    virtual void setPosition(const Vec2& var)
    {
        _lens3D->setPosition(var);
    }
    
    virtual const Vec2& getPosition() const
    {
        return _lens3D->getPosition();
    }
    
    static Lens3DTarget* create(Lens3D* pAction)
    {
        Lens3DTarget* pRet = new (std::nothrow) Lens3DTarget();
        pRet->_lens3D = pAction;
        pRet->autorelease();
        return pRet;
    }
private:

    Lens3DTarget()
        : _lens3D(nullptr)
    {}

    Lens3D* _lens3D;
};

void Effect4::onEnter()
{
    EffectAdvanceTextLayer::onEnter();
    //Node* gridNode = NodeGrid::create();
    
    auto lens = Lens3D::create(10, Size(32,24), Vec2(100,180), 150);
    auto move = JumpBy::create(5, Vec2(380,0), 100, 4);
    auto move_back = move->reverse();
    auto seq = Sequence::create( move, move_back, nullptr);

    /* In cocos2d-iphone, the type of action's target is 'id', so it supports using the instance of 'Lens3D' as its target.
        While in cocos2d-x, the target of action only supports Node or its subclass,
        so we make an encapsulation for Lens3D to achieve that.
    */

    auto director = Director::getInstance();
    auto pTarget = Lens3DTarget::create(lens);
    // Please make sure the target been added to its parent.
    this->addChild(pTarget);
    //gridNode->addChild(pTarget);

    director->getActionManager()->addAction(seq, pTarget, false);
    
    _bgNode->runAction( lens );
}

std::string Effect4::title() const
{
    return "Jumpy Lens3D";
}

//------------------------------------------------------------------
//
// Effect5
//
//------------------------------------------------------------------
void Effect5::onEnter()
{
    EffectAdvanceTextLayer::onEnter();

    //CCDirector::getInstance()->setProjection(DirectorProjection2D);
    
    auto effect = Liquid::create(2, Size(32,24), 1, 20);    

    auto stopEffect = Sequence::create(
                                         effect,
                                         DelayTime::create(2),
                                         StopGrid::create(),
                    //                     [DelayTime::create:2],
                    //                     [[effect copy] autorelease],
                                         nullptr);
    
    //auto bg = getChildByTag(kTagBackground);
    _bgNode->runAction(stopEffect);
}

std::string Effect5::title() const
{
    return "Test Stop-Copy-Restar";
}

void Effect5::onExit()
{
    EffectAdvanceTextLayer::onExit();

    Director::getInstance()->setProjection(Director::Projection::_3D);
}

//------------------------------------------------------------------
//
// Effect5
//
//------------------------------------------------------------------
void Issue631::onEnter()
{
    EffectAdvanceTextLayer::onEnter();
        
    auto effect = Sequence::create( DelayTime::create(2.0f), Shaky3D::create(5.0f, Size(5, 5), 16, false), nullptr);

    // cleanup
    //auto bg = getChildByTag(kTagBackground);
    removeChild(_bgNode, true);

    // background
    auto layer = LayerColor::create( Color4B(255,0,0,255) );
    addChild(layer, -10);
    auto sprite = Sprite::create("Images/grossini.png");
    sprite->setPosition(50,80);
    layer->addChild(sprite, 10);
    
    // foreground
    auto layer2BaseGrid = NodeGrid::create();
    auto layer2 = LayerColor::create(Color4B( 0, 255,0,255 ) );
    auto fog = Sprite::create("Images/Fog.png");

    BlendFunc bf = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA};
    fog->setBlendFunc(bf);
    layer2->addChild(fog, 1);
    addChild(layer2BaseGrid, 1);
    layer2BaseGrid->addChild(layer2);
    
    layer2BaseGrid->runAction( RepeatForever::create(effect) );
}

std::string Issue631::title() const
{
    return "Testing Opacity";
}

std::string Issue631::subtitle() const
{
    return "Effect image should be 100% opaque. Testing issue #631";
}

//------------------------------------------------------------------
//
// EffectAdvanceTextLayer
//
//------------------------------------------------------------------

enum
{
    IDC_NEXT = 100,
    IDC_BACK,
    IDC_RESTART
};

static int sceneIdx = -1; 

#define MAX_LAYER    6

Layer* nextEffectAdvanceAction();
Layer* backEffectAdvanceAction();
Layer* restartEffectAdvanceAction();

Layer* createEffectAdvanceLayer(int nIndex)
{
    switch(nIndex)
    {
        case 0: return new Effect3();
        case 1: return new Effect2();
        case 2: return new Effect1();
        case 3: return new Effect4();
        case 4: return new Effect5();
        case 5: return new Issue631();
    }  

    return nullptr;
}

Layer* nextEffectAdvanceAction()
{
    sceneIdx++;
    sceneIdx = sceneIdx % MAX_LAYER;

    auto layer = createEffectAdvanceLayer(sceneIdx);
    layer->autorelease();

    return layer;
}

Layer* backEffectAdvanceAction()
{
    sceneIdx--;
    int total = MAX_LAYER;
    if( sceneIdx < 0 )
        sceneIdx += total;    
    
    auto layer = createEffectAdvanceLayer(sceneIdx);
    layer->autorelease();

    return layer;
}

Layer* restartEffectAdvanceAction()
{
    auto layer = createEffectAdvanceLayer(sceneIdx);
    layer->autorelease();

    return layer;
} 


void EffectAdvanceTextLayer::onEnter(void)
{
    BaseTest::onEnter();
    
    _bgNode = NodeGrid::create();
    _bgNode->setAnchorPoint(Vec2(0.5,0.5));
    addChild(_bgNode);
    //_bgNode->setPosition( VisibleRect::center() );
    auto bg = Sprite::create("Images/background3.png");
    bg->setPosition( VisibleRect::center() );
    //addChild(bg, 0, kTagBackground);
    //bg->setPosition( VisibleRect::center() );
    _bgNode->addChild(bg);

    _target1 = NodeGrid::create();
    _target1->setAnchorPoint(Vec2(0.5,0.5));
    auto grossini = Sprite::create("Images/grossinis_sister2.png");
    _target1->addChild(grossini);
    _bgNode->addChild(_target1);
    _target1->setPosition(VisibleRect::left().x+VisibleRect::getVisibleRect().size.width/3.0f, VisibleRect::bottom().y+ 200);
    auto sc = ScaleBy::create(2, 5);
    auto sc_back = sc->reverse();
    _target1->runAction( RepeatForever::create(Sequence::create(sc, sc_back, nullptr) ) );


    _target2 = NodeGrid::create();
    _target2->setAnchorPoint(Vec2(0.5,0.5));
    auto tamara = Sprite::create("Images/grossinis_sister1.png");
    _target2->addChild(tamara);
    _bgNode->addChild(_target2);
    _target2->setPosition(VisibleRect::left().x+2*VisibleRect::getVisibleRect().size.width/3.0f,VisibleRect::bottom().y+200);
    auto sc2 = ScaleBy::create(2, 5);
    auto sc2_back = sc2->reverse();
    _target2->runAction( RepeatForever::create(Sequence::create(sc2, sc2_back, nullptr) ) );    

}

EffectAdvanceTextLayer::~EffectAdvanceTextLayer(void)
{
}

std::string EffectAdvanceTextLayer::title() const
{
    return "No title";
}

std::string EffectAdvanceTextLayer::subtitle() const
{
    return "";
}

void EffectAdvanceTextLayer::restartCallback(Ref* sender)
{
    auto s = new (std::nothrow) EffectAdvanceScene();
    s->addChild(restartEffectAdvanceAction()); 

    Director::getInstance()->replaceScene(s);
    s->release();
}

void EffectAdvanceTextLayer::nextCallback(Ref* sender)
{
    auto s = new (std::nothrow) EffectAdvanceScene();
    s->addChild( nextEffectAdvanceAction() );
    Director::getInstance()->replaceScene(s);

    s->release();
}

void EffectAdvanceTextLayer::backCallback(Ref* sender)
{
    auto s = new (std::nothrow) EffectAdvanceScene();
    s->addChild( backEffectAdvanceAction() );
    Director::getInstance()->replaceScene(s);
    s->release();
} 

void EffectAdvanceScene::runThisTest()
{
    auto layer = nextEffectAdvanceAction();

    addChild(layer);
    Director::getInstance()->replaceScene(this);
}