#include <list>

class SpringNode;

typedef std::list<SpringNode*> NeighborList;

class SpringNode {
public:
    SpringNode()
    {
        m_position = vec2(0, 0);
        m_velocity = vec2(0, 0);
        m_mass = 1;
        m_pinned = false;
    }
    void Pin()
    {
        m_pinned = true;
    }
    void SetPosition(const vec2& p)
    {
        m_position = p;
    }
    vec2 GetPosition() const
    {
        return m_position;
    }
    void AddNeighbor(SpringNode* node)
    {
        m_neighbors.push_back(node);
    }
    void ResetForce(vec2 force)
    {
        m_force = force;
    }
    void ComputeForce()
    {
        const float SpringConstant = 2;
        const float RestLength = 0.075f;
        const float DampingConstant = 0.2f;
        
        NeighborList::const_iterator n = m_neighbors.begin();
        for (; n != m_neighbors.end(); ++n) {

            // バネの力を計算する
            vec2 v = (*n)->m_position - m_position;
            float length = v.Length();
            vec2 direction = v.Normalized();
            vec2 restoringForce = direction * SpringConstant * (length - RestLength);

            // 減衰力を計算する
            vec2 relativeVelocity = (*n)->m_velocity - m_velocity;
            vec2 dampingForce = relativeVelocity * DampingConstant;
            
            // 2つの力をこのノードに加算し、隣接するノードから減算する
            vec2 totalForce = restoringForce + dampingForce;
            m_force += totalForce;
            (*n)->m_force -= totalForce;
        }
    }
    void Update(float dt)
    {
        const float SimulationSpeed = 0.2f;

        if (m_pinned)
            return;
        
        vec2 acceleration = m_force / m_mass;
        m_velocity += acceleration;
        m_position += m_velocity * dt * SimulationSpeed;
    }
private:
    vec2 m_force;
    vec2 m_position;
    vec2 m_velocity;
    float m_mass;
    bool m_pinned;
    NeighborList m_neighbors;
};
