//
//  BlocksLayer.cpp
//  RedCore2
//
//  Created by Gabriel Capella on 01/06/17.
//
//

#include "BlocksLayer.h"
#include "params.h"

USING_NS_CC;

void BlocksLayer::setLevel(int level) {
    auto visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 center = Vec2(visibleSize.width/2, visibleSize.height/2);
    int count = 0, i, j;
    int circles_n;
    double p_indus = 0;
    double size = CORE_RADIUS*0.75;
    int delta = 15;
    
    // Codigo feio para gerar fases aleatorias
    for (i = 0; count <= level; i++) {
        for (j = 0; count <= level && j <= i; j++) {
            if (i + 1 > delta) {
                delta *= 1.5;
                size /= 1.5;
                i = 0;
            }
            circles_n = i + 1;
            p_indus = j * 0.035;
            count++;
        }
    }
    
    this->setPosition(center);
    
    // aumentar aqui
    for (int i = circles_n - 1; i >= 0; i--) {
        auto circle = createCircle(size, i, 10, p_indus);
        this->addChild(circle, 9);
    }
    
    auto physicsBody = PhysicsBody::createCircle(CORE_RADIUS, PhysicsMaterial(0.1f, 1.0f, 0.0f));
    physicsBody->setGravityEnable(false);
    physicsBody->setVelocity(Vec2(0,0));
    physicsBody->setLinearDamping(0);
    physicsBody->setDynamic(false);
    physicsBody->setGroup(-1);
    physicsBody->setContactTestBitmask(0xFFFFFFFF);
    //physicsBody->setPositionOffset(center);
    
    auto core = DrawNode::create();
    //core->drawCircle(center, CORE_RADIUS, M_PI, 30, false, Color4F(COLOR_blue));
    core->drawDot(Vec2(), CORE_RADIUS, COLOR_red);
    core->addComponent(physicsBody);
    core->setTag(CORE_TAG);
    this->addChild(core, 40);
    
}

// on "init" you need to initialize your instance
bool BlocksLayer::init() {
    return true;
}

Node* BlocksLayer::createCircle (double size, int number, int number_of_segments, double p) {
    auto node = Node::create();
    double interna = number * size + CORE_RADIUS;
    double externa = (1 + number) * size + CORE_RADIUS;
    
    double* points = new double[number_of_segments+2];
    
    for (int i = 0; i < number_of_segments; i++) {
        points[i] = 2.0*M_PI/number_of_segments * i;
        points[i] += rand_minus1_1()*0.9*M_PI/number_of_segments;
    }
    //std::sort(points, points+number_of_segments);
    points[number_of_segments] = points[0] + 2*M_PI;
    
    for (int i = 0; i < number_of_segments; i++) {
        
        auto seg = createSegment(interna, externa, points[i], points[i+1], p >= rand_0_1());
        node->addChild(seg);
    }
    auto back = DrawNode::create();
    back->drawDot(Vec2(), interna+2, Color4F(COLOR_back));
    node->addChild(back, 1);
    
    auto rotate = RotateBy::create(1, rand_minus1_1()*30.0);
    
    node->runAction(RepeatForever::create(rotate));
    
    delete [] points;
    return node;
    
}

Node* BlocksLayer::createSegment (double r_internal, double r_externa, double begin, double end, bool especial) {
    int i;
    double sinV, cosV, step;
    auto draw = DrawNode::create();
    
    // borda
    begin += 1/r_externa;
    end -= 1/r_externa;
    
    int ns_ex_draw; // numeros de segmentos externos do desenho
    int ns_in_phy; // numeros de segmentos internos da fisica
    int ns_ex_phy; // numeros de segmentos externos do da fisica
    
    ns_ex_draw = (end - begin)*sqrt(r_externa)/1.5;
    ns_ex_phy = (end - begin)*sqrt(r_externa)/4.0;
    ns_in_phy = (end - begin)*sqrt(r_internal)/4.0;
    
    // Previne segmentos muito errados!
    if (ns_ex_draw < 2) ns_ex_draw = 2;
    if (ns_ex_phy < 2) ns_ex_phy = 2;
    if (ns_in_phy < 2) ns_in_phy = 2;
    
    std::vector<Vec2> p_ex_draw(ns_ex_draw+2); // pontos do arco para desenho
    p_ex_draw[ns_ex_draw+1] = Vec2();
    
    std::vector<Vec2> p_physics(ns_in_phy+ns_ex_phy+2); // pontos da fisica
    
    
    step = (end - begin)/(double)ns_ex_draw;
    for (i = 0; i <= ns_ex_draw; i++) {
        sinV = sin(begin + step * (double) i) * r_externa;
        cosV = cos(begin + step * (double) i) * r_externa;
        p_ex_draw[i] = Vec2 (sinV, cosV);
    }
    
    step = (end - begin)/(double)ns_ex_phy;
    for (i = 0; i <= ns_ex_phy; i++) {
        sinV = sin(begin + step * (double) i) * r_externa;
        cosV = cos(begin + step * (double) i) * r_externa;
        p_physics[i] = Vec2 (sinV, cosV);
    }
    
    step = (end - begin)/(double)ns_in_phy;
    for (i = 0; i <= ns_in_phy; i++) {
        sinV = sin(begin + step * (double) i) * r_internal;
        cosV = cos(begin + step * (double) i) * r_internal;
        p_physics[ns_ex_phy - i + 1 + ns_in_phy] = Vec2 (sinV, cosV);
    }
    
    Color4B color;
    if (!especial)
        color = Color4B(102*(rand_0_1()/5+0.5), 217*(rand_0_1()/5+0.5), 239*(rand_0_1()/5+0.5), 255);
    else
        color = Color4B(COLOR_orange);
    draw->drawSolidPoly(p_ex_draw.data(), ns_ex_draw + 2, Color4F(color));
    
    auto physicsBody = PhysicsBody::createEdgePolygon(p_physics.data(), ns_in_phy+ns_ex_phy+2, PhysicsMaterial(0.1f, 1.0f, 0.0f));
    physicsBody->setGravityEnable(false);
    physicsBody->setDynamic(false);
    physicsBody->setContactTestBitmask(0xFFFFFFFF);
    physicsBody->setGroup(-1);
    
    draw->addComponent(physicsBody);
    if (!especial)
        draw->setTag(BLOCK_TAG);
    else
        draw->setTag(INDESTRUCTIBLE_BLOCK_TAG);
    
    return draw;
}