function AnimBreakout(canvas)
{
    // offsets
    var playFieldX = 3;
    var playFieldY = 2;
    var playFieldWidth = 28;
    var playFieldHeight = 18;
    
    var bricksX = playFieldX;
    var bricksY = playFieldY;
    var bricksWidth = playFieldWidth;
    var bricksHeight = playFieldHeight - 8;
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    var paddleMinX = playFieldX;
    var paddleMaxX = playFieldX + playFieldWidth;
    var paddleY = 20;
    var currentPaddleX = 0;
    
    var ballX = 0;
    var ballY = 0;
    var ballCol = "#9988FF";
    
    // sprites
    var spriteArray = new Array(5);
    spriteArray[0] = SpriteArk1;
    spriteArray[1] = SpriteArk2;
    spriteArray[2] = SpriteArk3;
    spriteArray[3] = SpriteArk4;
    spriteArray[4] = SpriteArk5;

    // levels
    var levelWidth = 14;
    var levelHeight = 9;
    var level1 = new Array(
    0,1,1,1,1,1,3,3,1,1,1,1,1,0,
    0,2,2,2,2,3,2,2,3,2,2,2,2,0,
    0,3,3,3,3,3,4,4,3,3,3,3,3,0,
    0,5,5,5,5,3,5,5,3,5,5,5,5,0,
    0,4,4,4,4,4,3,3,4,4,4,4,4,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,    
    0,0,0,0,0,0,0,0,0,0,0,0,0,0
    );
    
    var levels = new Array(1);
    levels[0] = level1;
    
    var currentLevelArray = new Array(levelWidth*levelHeight);
    var currentLevelId = 0;
    
    
    
    var g = canvas;
    
    // states
    var STATE_NONE = -1;
    var STATE_LOAD = 0;
    var STATE_INGAME = 1;
    var STATE_LOSTBALL = 2;

    var NUMBER_OF_STATES = 3;    
    var m_stateDuration = new Array(NUMBER_OF_STATES);
    var states = new Array(NUMBER_OF_STATES);
    var m_nextState = new Array(NUMBER_OF_STATES);
    
    // state defs 
    m_stateDuration[STATE_LOAD] = 15/SPEEDER_BREAKOUT;       m_nextState[STATE_LOAD] = STATE_INGAME;        
    m_stateDuration[STATE_INGAME] = 786/SPEEDER_BREAKOUT;    m_nextState[STATE_INGAME] = STATE_NONE;      
    m_stateDuration[STATE_LOSTBALL] = -1;    m_nextState[STATE_LOSTBALL] = STATE_INGAME;  
    
    var durationLostBall = 8/SPEEDER_BREAKOUT;
    var stateLostBallTimer = 0;
    var currentState = 0;  
    
    var DURATION = 0;
    for (var i = 0; i < m_stateDuration.length; i++)
    {
        if (m_stateDuration[i]>0)
            DURATION+=m_stateDuration[i];
    }
    var m_duration = DURATION;       
    var m_timeLastChange = m_duration;
    
    //////////////////////////////////////////////////////
    this.Update = function()
    {
        switch (currentState)
        {
            case STATE_LOAD:
            {
                var level = levels[currentLevelId];
                for (var i = 0; i < level.length; i++)
                {
                    currentLevelArray[i]= level[i];
                }
                g.ClearScreen("#223322"); 
                DrawGame();
            }
            break;
            
            case STATE_INGAME:
            {
                g.ClearScreen("#000000");            
                UpdateGame();
                DrawGame();
                DrawBall();
            }
            break;
            case STATE_LOSTBALL:
            {
                g.ClearScreen(ballCol); 
                DrawGame();
                stateLostBallTimer--;
                if (stateLostBallTimer<=0)
                {
                    currentState = STATE_INGAME;
                    return true;
                }
            }
            break;            
        }
        
        // automatic state change
        if ((m_timeLastChange - m_stateDuration[currentState]) >= m_duration)
        {
            if (m_stateDuration[currentState]>0)
            {
                currentState = m_nextState[currentState];
                m_timeLastChange = m_duration;
            }
        }
        // timer
        m_duration--;
        if (m_duration <= 0)
        {
            return false;
        }
        return true; 
    }
    
    /////////////////////////////////////////////////////////////////////////////////////////////////
    function DrawGame()
    {
        g.DrawSprite(SpriteArkbk, 0, 0);
        g.DrawSprite(SpriteArk_paddle, currentPaddleX - (SpriteArk_paddle.w/2), paddleY);
        
        // draw game scene
        var numOfBricks = levelWidth*levelHeight;
        var x = bricksX;
        var y = bricksY;
        var maxX = playFieldWidth + x;
        for (var i = 0; i < numOfBricks; i++)
        {
            var brickId = currentLevelArray[i]-1;
            
            if (brickId>=0)
                g.DrawSprite(spriteArray[brickId], x, y);
            
            x+=2;
            if (x>=maxX)
            {
                x = bricksX;
                y+=2
            }    
        }
    }    
    
    function DrawBall()
    {
        // draw ball
        var ball_X = Math.floor(ballX/ballSpeedFactor);
        var ball_Y = Math.floor(ballY/ballSpeedFactor);    
        g.PutPixel(ball_X, ball_Y, ballCol);    
    }
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////
    var ballSpeedX = 0;
    var ballSpeedY = 0;
    var ballSpeedFactor = 10;
  
    function UpdateGame()
    {
       var oldBallX = ballX;
       var oldBallY = ballY;
       
       // upper check
       var oldPosX = Math.floor(ballX/ballSpeedFactor);
       var oldPosY = Math.floor(ballY/ballSpeedFactor); ;
       
        ballX+=ballSpeedX;
        ballY+=ballSpeedY;              
        
        // game pos        
        var ball_X = Math.floor(ballX/ballSpeedFactor);
        var ball_Y = Math.floor(ballY/ballSpeedFactor);    
            
        //DebugOut("ball:" + ball_X +","+ball_Y + "/" + ballSpeedX + "," + ballSpeedY  + "/paddlY:" + paddleY);
       
        if (ball_Y<0)
        {
            ballSpeedY=Math.abs(ballSpeedY);
            DebugOut("over the top " + ballY);
        }
            
        // paddle check
        if (ball_Y>=(paddleY-1))
        {
            var halfPad = Math.floor(SpriteArk_paddle.w/2);
            var padMinX = currentPaddleX - halfPad;
            var padMaxX = currentPaddleX + halfPad;
            
            if ((ball_X > padMinX) && (ball_X < padMaxX))
            {
                var oldBallSpeedX = ballSpeedX;
                ResetBallSpeed();
                
                if ((oldBallSpeedX<0 && ballSpeedX>0) || (oldBallSpeedX>0 && ballSpeedX<0))
                {
                    // make sure that ball doesn't changes x direction
                    ballSpeedX = -ballSpeedX;
                }
            }
        }
        
        // lower check
        if (ball_Y > paddleY)
        {
            ResetBall();
            if (ballSpeedY>0)
                ballSpeedY=-ballSpeedY;     
            DebugOut("over the bottom " + ballSpeedY);   
            currentState = STATE_LOSTBALL;    
            stateLostBallTimer = durationLostBall;
            return;                    
        }
        
        // right check 
        if ((ball_X<=bricksX) || (ball_X>=(bricksX+bricksWidth)))
        {
            ballSpeedX = -ballSpeedX;
            ballX+=ballSpeedX;
        }
        
       
        // check collision with brick
        var posX = Math.floor((ball_X - bricksX) / 2);
        var posY = Math.floor((ball_Y - bricksY) / 2);
        var levelPos = (posY * levelWidth + posX);
        var brickId = currentLevelArray[levelPos];
        
        if (brickId>0)
        {
            // what direction did we come from?
            var arrayX = Math.floor((oldPosX - bricksX) / 2);
            var arrayY = Math.floor((oldPosY - bricksY) / 2);
            
            if ((arrayY>posY)||(arrayY<posY))
            {
                // we came from the bottom
                ballSpeedY = -ballSpeedY;
                var noiseAmplitudeY = (ballSpeedY)/4; 
                var noiseY = (Math.random()*noiseAmplitudeY);
                ballSpeedY -= Math.floor(noiseY);
                if (Math.abs(ballSpeedY) < (ballSpeedFactor/2))
                    ballSpeedY = (ballSpeedFactor/2);
                if (noiseAmplitudeY<0)
                    ballSpeedY = - ballSpeedY;
                    
            }
            else if ((arrayX>posX)||(arrayX<posX))
            {
                // we came from the right
                ballSpeedX = -ballSpeedX;
                var noiseAmplitudeX = (ballSpeedX)/4;      
                var noiseX = (Math.random()*noiseAmplitudeX);      
                ballSpeedX -= Math.floor(noiseX);
            }
            
            currentLevelArray[levelPos]=0;
            
            if (Math.abs(ballSpeedY) <= 2)
            {
                ballSpeedY = ballSpeedFactor/2;
            }      
            
            DebugOut("coll");
            
            ballX = oldBallX;
            ballY = oldBallY;            
        }
        
        // move paddle
        //if (m_duration%2 == 0)
        {
            if (currentPaddleX<ball_X)
                currentPaddleX++;
            else if (currentPaddleX>ball_X)
                currentPaddleX--;        
        }
    }
    
    function ResetBall()
    {
        ballX = currentPaddleX*ballSpeedFactor;
        ballY = (paddleY-1)*ballSpeedFactor;    
    }
    
    function ResetBallSpeed()
    {
        ballSpeedX = - (ballSpeedFactor/2) + Math.round(Math.random()*ballSpeedFactor*2);
        ballSpeedY = - (ballSpeedFactor/2) - Math.round(Math.random()*(ballSpeedFactor/2));  
        
        ballSpeedX = Math.floor(ballSpeedX/3)*4;  
        ballSpeedY = Math.floor(ballSpeedY/3)*4;
    }
    
    //////////////////////////////////////////////////////
    this.Reset = function()
    {
        m_duration = DURATION;  
        m_timeLastChange = m_duration;
        currentState = STATE_LOAD;  
        currentPaddleX = paddleMinX + (paddleMaxX-paddleMinX)/2; // center paddle
        ResetBall()
        ResetBallSpeed();
        currentLevelId = 0;
    }    

   
    function DebugOut(_msg)
    {
        var debug = document.getElementById("debug");
        if (debug)
            debug.innerHTML = _msg + "<br>" + debug.innerHTML ;            
    }

        
}
