
--[[
SceneSave
SceneClean
SceneUpdate
SceneEvent
--  s01_0505_photopuzzle.s01_0505_photopuzzle.L00_0200_puzzle01.sTable[i]
]]


L00_0200_puzzle01 = {}
L00_0200_puzzle01.sCount = 12


function OnSave()
   L00_0200_puzzle01:Save()
end

function OnLoad()
    L00_0200_puzzle01:Open_L00_0200()
end

function OnSceneExit()
    L00_0200_puzzle01:Save()
end

function OnUpdate()
    OldInterfaceMap.InjectSceneUpdateFunction()
end

--           minigame code:
---------------------------------------------------- utils --------------------------------------------------------------------------------------------

BringToFront=
function(elementName,relElement)  --  relElement  ==  nil or index or stringName,  if nil then #bkg.elements

	local elementIndex=bkg.elements[elementName]:GetRowIndex()
	local topElementIndex=1
	if relElement==nil then 
        topElementIndex = L00_0200_puzzle01.sCount
    end
	if type(relElement)=="string" then topElementIndex=bkg.elements[relElement]:GetRowIndex() end
	if type(relElement)=="number" then topElementIndex=relElement end 
	
	if elementIndex < topElementIndex
	then
		while elementIndex<(topElementIndex-1)
		do
			bkg.SwapElements(elementIndex,elementIndex+1)
			elementIndex=bkg.elements[elementName]:GetRowIndex()
		end
	else
		while elementIndex>(topElementIndex+1)
		do
			bkg.SwapElements(elementIndex,elementIndex-1)
			elementIndex=bkg.elements[elementName]:GetRowIndex()
		end	
	end

end

--

L00_0200_puzzle01 = {}
-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.vector(x,y,z)

	local v={x=x,y=y,z=z}

	mt = {
		__concat= function (v,string) return  mt.__tostring(v)..string  end,
		__tostring= function (v) return  v.x..","..v.y..","..v.z  end,
		__add= function (v1,v2) return L00_0200_puzzle01.vector(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)  end,
		__sub= function (v1,v2) return L00_0200_puzzle01.vector(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)  end,
		__mul= function (v,scalar) return L00_0200_puzzle01.vector(v.x*scalar,v.y*scalar,v.z*scalar)  end,
	 	__div= function(v,scalar) return L00_0200_puzzle01.vector(v.x/scalar,v.y/scalar,v.z/scalar)  end
	 }

	function v.Length()  return math.sqrt(v.x*v.x+v.y*v.y+v.z*v.z)  end
	function v.Normalize()  local length=v.Length(); v.x=v.x/length; v.y=v.y/length; v.z=v.z/length  end

    setmetatable(v, mt)
	return v
end


function L00_0200_puzzle01.SetSolvedFunction(solvedFunction)
    L00_0200_puzzle01.solvedFunction = solvedFunction
end

---------------------------------------------------- utils ---------------------------------end--------------------------------------------------------

function L00_0200_puzzle01.Init()

    L00_0200_puzzle01.canConnectWith={}             				-- @ TOSET

    
    -- TODO: override
    L00_0200_puzzle01.canConnectWith["seq_mk_puzzle1"]  =  {"seq_mk_puzzle2",    "seq_mk_puzzle4"}

    
            
    L00_0200_puzzle01.scenePrefix="seq_mk_puzzle"
    L00_0200_puzzle01.prefix=""..L00_0200_puzzle01.scenePrefix
    states.L00_0200_mk_puzzle=1
    L00_0200_puzzle01.sCount=12
    
    L00_0200_puzzle01.openTime=0
    L00_0200_puzzle01.snapLength=50
    L00_0200_puzzle01.draging = false
    
    L00_0200_puzzle01.borderSize = 30
    
    L00_0200_puzzle01.doubleClick = true
    
    L00_0200_puzzle01.topElement="spr_puzzle1_top"
    
    L00_0200_puzzle01.connectSound="reg_s00_0100_connect_pieces" 				-- @ TOSET
    
    L00_0200_puzzle01.pickUpPieceSound="reg_s00_0100_pick_up_piece"			-- @ TOSET
    L00_0200_puzzle01.dropPieceSound="reg_s00_0100_drop_piece"				-- @ TOSET
    L00_0200_puzzle01.flipPieceSound="reg_s00_0100_pick_up_piece"	
    
    L00_0200_puzzle01.rotateSound = "reg_s00_0100_drop_piece"
    
    function L00_0200_puzzle01:PlayRotationSound()  
        PlaySound(L00_0200_puzzle01.rotateSound)  
    end
        
    L00_0200_puzzle01.dragSprite=nil
    L00_0200_puzzle01.dragGroup=nil
    L00_0200_puzzle01.dragStartMPos=nil
    L00_0200_puzzle01.dragStartSPos=nil
    
    L00_0200_puzzle01.wasEnableSceneComments=true
    
    L00_0200_puzzle01.wasRMouse=false
    L00_0200_puzzle01.sTable={}
    L00_0200_puzzle01.gTable={}
    L00_0200_puzzle01.charactersStates={}
    L00_0200_puzzle01.normalRotation={2,3,4,1}
    L00_0200_puzzle01.normalRotationINV={-1,-1,-1,-1,6,7,8,5}
    
    L00_0200_puzzle01.connectCom="/abt_e_L00_00_0001_nico/"
    L00_0200_puzzle01.solvedCom="/abt_e_P01_0010_nico/"
    
    
    L00_0200_puzzle01.s_normal=1
    L00_0200_puzzle01.s_hover=2
    L00_0200_puzzle01.s_pressed=3
    
    L00_0200_puzzle01.zInndices = {}
    L00_0200_puzzle01.twoSides = true
    
    L00_0200_puzzle01.OnItemCallback = nil
    
    L00_0200_puzzle01.game_name = "unknown"
    
    
    L00_0200_puzzle01.leftMargin = 20
    L00_0200_puzzle01.rightMargin = 20
    L00_0200_puzzle01.topMargin = 100
    L00_0200_puzzle01.bottomMargin = 150
    
    
    L00_0200_puzzle01.randomRangeMinX = 150
    L00_0200_puzzle01.randomRangeMaxX = 1000  
    
    L00_0200_puzzle01.randomRangeMinY = 150
    L00_0200_puzzle01.randomRangeMaxY = 450    
    
    L00_0200_puzzle01.maxRMouseDown = 600

    L00_0200_puzzle01.isVisible = function()
        return true
    end
    

end

L00_0200_puzzle01.Init()



function L00_0200_puzzle01.SetSpriteFrame(name,frame)
    if frame <= 0 then return end
    local map = {}
    map[1] = 0
    map[2] = 90
    map[3] = 180
    map[4] = 270
    map[5] = 0
    map[6] = 90
    map[7] = 180
    map[8] = 270

    if frame > 4 then 
	    bkg.elements[name]:SetCurrentFrame(2)
    else
        bkg.elements[name]:SetCurrentFrame(1)
    end
    
    bkg.elements[name]:SetAngle(map[frame])
end
	

function L00_0200_puzzle01.GetSpriteFrame(this,name)
    local map = {}
    map[0] = 1
    map[90] = 2
    map[180] = 3
    map[270] = 4
    local map_inv = {}
    map_inv[0] = 5
    map_inv[90] = 6
    map_inv[180] = 7
    map_inv[270] = 8

	if bkg.elements[name]:GetCurrentFrame() == 2 then 
	    return map_inv[bkg.elements[name]:GetAngle()]
    else
        return map[bkg.elements[name]:GetAngle()]
    end
    
end


function L00_0200_puzzle01.setBackButtonState(state)   --  we can use: 	L00_0200_puzzle01.s_normal, 	L00_0200_puzzle01.s_hover, 	L00_0200_puzzle01.s_pressed
	--bkg.elements.puzzle1_back:SetCurrentFrame(state)
end


-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.SolvedPuzzleEvent(this)
  
    L00_0200_puzzle01.solvedFunction() 
end

-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.CSprite(s,relations,relationsINV,group,rightPos)
	-- s - sprite on scene , relations={},  -- table of sprites relations  == {"prefix1"=L00_0200_puzzle01.vector1,"prefix2"=L00_0200_puzzle01.vector2...} , group - element of L00_0200_puzzle01.gTable which contains result of this function - object L00_0200_puzzle01.CSprite
	return {s=s,relations=relations,relationsINV=relationsINV,group=group,rightPos=rightPos,e=function (this) return bkg.elements[this.s] end }
end

-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.InitMiniGame(this)
	this.sTable={}
	this.gTable={}
	this.charactersStates={}
end

-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.groupFromMousePos(this,x,y)

	local group_=nil
	local maxInGroup_=0
	local maxInSTable_=0
	local element=nil

	for i=1,#this.gTable
	do
		local mouseOnGroup=false
		for j=1,#this.gTable[i]
		do
			if this.gTable[i][j]:e():IsPointInside(x,y) and  this.gTable[i][j]:e():GetActive()==true	then	mouseOnGroup=true; 	end
		end

		if mouseOnGroup==true
		then
			for j=1,#this.gTable[i]
			do
				if this.gTable[i][j]:e():GetActive()==true and this.gTable[i][j]:e():GetRowIndex()>maxInGroup_  then maxInGroup_=this.gTable[i][j]:e():GetRowIndex(); group_=this.gTable[i]  end
			end
		end
	end


	for i=1,this.sCount
	do
		if this.sTable[i]:e():GetActive()==true and this.sTable[i]:e():GetRowIndex()>maxInSTable_ then maxInSTable_= this.sTable[i]:e():GetRowIndex() end
	end
	
	if group_~=nil
	then
		for i=1,#group_
		do
			if group_[i]:e():IsPointInside(x,y) and  group_[i]:e():GetActive()==true	then	element= group_[i]	end
		end
	end

	return {group=group_,maxInGroup=maxInGroup_, maxInSTable=maxInSTable_,element=element}
end

-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.CheckSolution(this)

	if states[L00_0200_puzzle01.game_name.."_int_solved"]==1 then return end
	local count=0
	for i=1,#this.gTable
	do
		if #this.gTable[i]>0 then count=count+1  end
	end

	if count==1
	then 

    
		this:SolvedPuzzleEvent()
		for i=1,this.sCount
		do
	   		this.sTable[i]:e():SetPosition(this.sTable[i].rightPos.x,this.sTable[i].rightPos.y)
            this.SetSpriteFrame(this.sTable[i].s,1)
	   		
		end
		
		states[L00_0200_puzzle01.game_name.."_int_solved"]=1
	end

end

-------------------------------------------------------------------------------------------
--          if direct == -1 then  rotate left otherwise right 90*numberOf90d degrees

function L00_0200_puzzle01.RotateZvector(this,v_,numberOf90d,direct)
	if direct==nil then direct =1 end

	for i=1,numberOf90d
	do
	    local old=this.vector(v_.x,v_.y,0);
	    v_.x = old.x*math.cos(direct*math.pi/2)  +old.y*math.sin(direct*math.pi/2)
		v_.y = -old.x*math.sin(direct*math.pi/2) +old.y*math.cos(direct*math.pi/2)
	end
end

-------------------------------------------------------------------------------------------
--		switch to next frame sprite and all of group which contain it
function L00_0200_puzzle01.RotateSprite(this,sprite)
	if IsMouseButtonDown(MB_LEFT)==true then return end 
	local x,y=sprite:e():GetPosition()
	local group=sprite.group
	local group_size=#group
	for i=1,group_size
	do
		if group[i].INV==true
		then 
            this.SetSpriteFrame(group[i].s,this.normalRotationINV[this:GetSpriteFrame(group[i].s)])
		else
            this.SetSpriteFrame(group[i].s,this.normalRotation[this:GetSpriteFrame(group[i].s)])
		end
	end
	this:SetSpriteGroupPosition(sprite)
	this:PlayRotationSound()

end

-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.SetSpriteGroupPosition(this,sprite)

	local G=sprite.group
	local G_size=#G
	for i=1,G_size
	do
		if G[i]~=sprite
		then
			
			local rel_vec={}
			
			if this:GetSpriteFrame(sprite.s)<=4
			then
				rel_vec = this.vector(sprite.relations[G[i]:e():GetName()].x,sprite.relations[G[i]:e():GetName()].y,0)
			else
				rel_vec = this.vector(sprite.relationsINV[G[i]:e():GetName()].x,sprite.relationsINV[G[i]:e():GetName()].y,0)
			end
		
			this:RotateZvector(rel_vec,(this:GetSpriteFrame(sprite.s)-1),-1)
			local x,y=sprite:e():GetPosition()
			local pos=this.vector(x,y,0)+rel_vec
			G[i]:e():SetPosition(pos.x,pos.y)
		end
	end

end

-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.RestoreSprite(this,sprite,byName)

	if byName then local name=sprite;  sprite={} sprite.s= bkg.elements[name]:GetName()  end

	local x,y=sprite:e():GetPosition()

	if x<L00_0200_puzzle01.leftMargin
	then
		sprite:e():SetPosition(L00_0200_puzzle01.leftMargin,y)
		x,y=sprite:e():GetPosition()
		if not byName
		then
			this:SetSpriteGroupPosition(sprite)
		end
	end

	if x>OldInterfaceMap.width-L00_0200_puzzle01.rightMargin
	then
		sprite:e():SetPosition(OldInterfaceMap.width-L00_0200_puzzle01.rightMargin,y)
		x,y=sprite:e():GetPosition()
		if not byName
		then
			this:SetSpriteGroupPosition(sprite)
		end
	end

	if y<L00_0200_puzzle01.topMargin
	then
		sprite:e():SetPosition(x,L00_0200_puzzle01.topMargin)
		x,y=sprite:e():GetPosition()
		if not byName
		then
			this:SetSpriteGroupPosition(sprite)
		end
	end

	if y>OldInterfaceMap.height - L00_0200_puzzle01.bottomMargin
	then
		sprite:e():SetPosition(x,OldInterfaceMap.height-L00_0200_puzzle01.bottomMargin)
		if not byName
		then
			this:SetSpriteGroupPosition(sprite)
		end
	end
end
	
-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.RestoreSprites(this,group)

	if this.sCount==0 then return end

	local x,y=group[1]:e():GetPosition()

	for i=1,#group
	do
		this:RestoreSprite(group[i])
	end
end

	
	
-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.SaveSwapElements(this,i,j)
	local ret=bkg.SwapElements(i,j)
end
	
-------------------------------------------------------------------------------------------

function Helper(i , j, elem, name, topIndex )
    local elemj = bkg.elements[j+1]
    return j < (topIndex - 1) and elemj ~= nil and elemj:GetName() ~= name
end

function L00_0200_puzzle01.groupToTop(this,group) -- todo  sortowanie kawalkow
    local topIndex = bkg.elements[L00_0200_puzzle01.topElement]:GetRowIndex()
	if this.sCount==1 then return end
       
	for i=1, #group do
	    local j=group[i]:e():GetRowIndex()

	    while Helper(i, j, bkg.elements[j+1], this.topElement, topIndex)  -- and string.sub(bkg.elements[j+1]:GetName(),1,string.len(L00_0200_puzzle01.prefix))==L00_0200_puzzle01.prefix
	    do
			this:SaveSwapElements(j, j+1)
	    	j=j+1
	    end
	end    
end


function L00_0200_puzzle01.spriteToTop(this,spriteName)
	if spriteName==nil then return end 
	
	if g_puzzle1Open
	then
		for i=1,this.sCount
		do
			if spriteName==this.sTable[i].s
			then
				this:groupToTop(this.sTable[i].group)
				break
			end
		end
	end
end

-------------------------------------------------------------------------------------------

function FetchElement(table,nr)

	if #table == 0 then return nil end
	local ret = table[nr]
	table[nr] = table[#table]
    table[#table] = nil
    return ret
end
	
-------------------------------------------------------------------------------------------
--   try connect two groups , assumption is dragGroup different addGroup

function L00_0200_puzzle01.TryConnect(this,dragGroup,addGroup)

    local inv = this:GetSpriteFrame(dragGroup[1].s)>4

	local rightRel={}
	if not inv
	then
  
		rightRel=dragGroup[1].relations[addGroup[1]:e():GetName()]
	else
   
		rightRel=dragGroup[1].relationsINV[addGroup[1]:e():GetName()]
	end
		
	if rightRel==nil then return false 	end

	local expectRel = L00_0200_puzzle01.vector(rightRel.x,rightRel.y,0) -- to set final position


	this:RotateZvector(expectRel,(this:GetSpriteFrame(dragGroup[1].s)-1),-1)


   
	local x0,y0=dragGroup[1]:e():GetPosition()
	local x1,y1=addGroup[1]:e():GetPosition()
	local currRel=this.vector(x1-x0,y1-y0,0)

	if (expectRel-currRel).Length()<this.snapLength  and  addGroup[1]:e():GetActive()==true --and dragGroup[1].s:GetActive()==true
	then
	    
		this.canII=false
		if this.canConnectWith
		then
		
			local  canConnect=false 
			
			for i=1,#dragGroup
			do
				local firstName=dragGroup[i]:e():GetName()
				for j=1,#addGroup
				do
					local secondName=addGroup[j]:e():GetName()
					local canConnectWithFirstName=this.canConnectWith[firstName]

					if canConnectWithFirstName
					then
						for k=1,#canConnectWithFirstName
						do
							if canConnectWithFirstName[k]==secondName then canConnect=true break end
						end
					end
				end
			end
			
			if canConnect==false 
			then
				for i=1,#addGroup
				do
					local firstName=addGroup[i]:e():GetName()
					for j=1,#dragGroup
					do
						local secondName=dragGroup[j]:e():GetName()
						local canConnectWithFirstName=this.canConnectWith[firstName]
	
						if canConnectWithFirstName
						then
							for k=1,#canConnectWithFirstName
							do
								if canConnectWithFirstName[k]==secondName then 
								canConnect=true break end
							end
						end
					end
				end
			end
			
			if canConnect==false  then   return false end
		end

		local x,y=addGroup[1]:e():GetPosition()

		dragGroup[1]:e():SetPosition(x-expectRel.x,y-expectRel.y) -- translate
		this:SetSpriteGroupPosition(dragGroup[1])

		for i=1,#addGroup
		do
			table.insert(dragGroup,addGroup[i])
			addGroup[i].group=dragGroup
		end

		for i=1,#this.gTable
		do
			if this.gTable[i]==addGroup then  this.gTable[i] = {} break; end
		end

		table.remove(addGroup)
		
		this:groupToTop(dragGroup)
		return true
	end
	return false
end

function L00_0200_puzzle01.ItemMouseUp(this,itemName)
		Inventory.Release()
		return
end

function L00_0200_puzzle01.TryConnectAll(this)

	for i=1,#this.gTable  --  todo make function
	do
		if #this.gTable[i]>0 and #this.gTable[i]<this.sCount and this.gTable[i]~={} and this.dragGroup~=this.gTable[i] and this:GetSpriteFrame(this.dragGroup[1].s) == this:GetSpriteFrame(this.gTable[i][1].s)
		then
			if this:TryConnect(this.dragGroup,this.gTable[i]) 
			then
				--if this.res 
				--then  
					this:ConnectEvent()
					this:CheckSolution() 
				--end 
			end
		end
	end
	
	this:CheckSolution()

end
-------------------------------------------------------------------------------------------
-- stop L00_0200_puzzle01.draging

function L00_0200_puzzle01.MouseUp(this,dragSprite)
  
	local x, y = GetMousePos()
	local mousePos=this.vector(x,y,0)

	this.res=false
	if	states[L00_0200_puzzle01.game_name.."_int_solved"]==0					-- stop L00_0200_puzzle01.draging
	then
		this:TryConnectAll()
	end

    if L00_0200_puzzle01.OnMouseCallback then
         L00_0200_puzzle01.OnMouseCallback()
    end 	
end

-------------------------------------------------------------------------------------------
function L00_0200_puzzle01.DoubleClick(this,elem)
	-----------------  inversion : 
    PlaySound(this.flipPieceSound)
	for j=1,#elem.group
	do
		if elem.group[j].INV==true then  elem.group[j].INV=false else elem.group[j].INV=true end
		
		if elem.group[j].INV==true
		then
            this.SetSpriteFrame(elem.group[j].s,this:GetSpriteFrame(elem.group[j].s)+4)
		else
            this.SetSpriteFrame(elem.group[j].s,this:GetSpriteFrame(elem.group[j].s)-4)
		end	
	end
	this:SetSpriteGroupPosition(elem)
	
	
	this:TryConnectAll()
	-----end---------  inversion : 
	
end

function L00_0200_puzzle01.SceneEvent(this,element, item)

    if item~=nil and L00_0200_puzzle01.OnItemCallback~=nil then
        L00_0200_puzzle01.OnItemCallback(item)
    end

	--# if element=="puzzle1_back" then Sleep(200) OldAction("undefine",function() this:Close_L00_0200() end )   return end
	if element=="puzzle1_spr_minigame_yes" then this:SolvedPuzzleEvent() return end

	local lastClick=this.lastClick
	this.lastClick=GetTime()

	if lastClick==nil then  lastClick =this.lastClick-10000 end
    
    local dT = GetTime() - lastClick

	
	if item~=nil then this:ItemMouseUp(item) end
	if item~=nil then return end

	if element==this.topElement and item == nil	then Sleep(100) OldAction ("undefined",function() Sleep(1)  this:Close_L00_0200() end)  return false end

	if true or string.sub(element,1,string.len(this.prefix))==this.prefix --and states.s01_0505_photopuzzle_solved==0
	then

        --local middle= IsMouseButtonDown(2)==true
       -- printmsg("MINIGAME",element)
        
            
        local mX,mY = GetMousePos()
        
        if not L00_0200_puzzle01.doubleClick then
            local rel = this:CursorElementRelation(bkg.elements[element],mX,mY)
                
            if rel == "center" or L00_0200_puzzle01.twoSides == false then
                --return "curs_rt"
            elseif rel == "border" then
                for i=1,this.sCount
                    do
                        if element == this.sTable[i].s
                        then
                            this:DoubleClick(this.sTable[i]) 
                            this:groupToTop(this.sTable[i].group)
                            PlaySound2d(this.pickUpPieceSound)
                            return
                        end
                    end
                return 
            else
            end
        else
        --
            if dT > 0.2 or L00_0200_puzzle01.twoSides == false then
            else
                for i=1,this.sCount
                    do
                        if element == this.sTable[i].s
                        then
                            this:DoubleClick(this.sTable[i]) 
                            this:groupToTop(this.sTable[i].group)
                            PlaySound2d(this.pickUpPieceSound)
                            return
                        end
                    end
                return 
            end
        --
        end

		this.canII=true
		
		for i=1,this.sCount do

		    if element == this.sTable[i].s
		    then
		    	this:groupToTop(this.sTable[i].group)
		    	break
		    end
		end

		for i=1,this.sCount
		do


		    if element == this.sTable[i].s then
            
			    this.dragSprite=this.sTable[i]
			    this.dragGroup=this.dragSprite.group
			    PlaySound2d(this.pickUpPieceSound)
		    	break
		    end
		end

	    this.draging=true
	    local x,y = this.dragSprite:e():GetPosition()
	    this.dragStartSPos=this.vector(x,y,0)
	    x, y = GetMousePos()
		this.dragStartMPos=this.vector(x,y,0)


	end
	
	
end

-------------------------------------------------------------------------------------------
function MMouseDown()

end

function L00_0200_puzzle01.ConnectEvent(this)
	PlaySound(this.connectSound) 
end

function L00_0200_puzzle01.RMouseDown(this)

    local x,y=GetMousePos()

    if not L00_0200_puzzle01.isVisible() or y > L00_0200_puzzle01.maxRMouseDown then
        return 
    end

	if this.openTime~=0 and ( y>=OldInterfaceMap.height and (GetTime()-this.openTime)>300) then this:Close_L00_0200() return  end
	
	if y>=OldInterfaceMap.height then return end
	
	local ret=this:groupFromMousePos(x,y)
	if --[[states.s01_0505_photopuzzle_solved==0 and ]]  ret.group
	then
       
		this:groupToTop(ret.group)

		this.res=false
        
		this:RotateSprite(ret.element)	-- only  rotation

		for i=1,#this.gTable  --  todo make function
		do
			if #this.gTable[i]>0 and #this.gTable[i]<this.sCount and ret.group~=this.gTable[i] and this:GetSpriteFrame(ret.element.s) == this:GetSpriteFrame(this.gTable[i][1].s)
			then if this:TryConnect(ret.group,this.gTable[i]) then this.res= true end end
		end
		L00_0200_puzzle01:RestoreSprites(ret.group)

		if this.res==true
		then
			this:ConnectEvent()
			L00_0200_puzzle01:CheckSolution()
		end
       
	end
    
    if L00_0200_puzzle01.OnMouseCallback then
         L00_0200_puzzle01.OnMouseCallback()
    end     
end
	
-------------------------------------------------------------------------------------------


function L00_0200_puzzle01.ElementFromMousePos(this,mX,mY)
    local suspectedElements = {}
    
    for i=1,L00_0200_puzzle01.sCount do
        local elem = bkg.elements["seq_mk_puzzle"..i]
        if elem:IsPointInside(mX,mY) then 
            suspectedElements[#suspectedElements+1] = elem 
        end
    end
    
    if #suspectedElements == 0 then return end
    
    local maxElem  = suspectedElements[1]
    local maxIndex = suspectedElements[1]:GetRowIndex()
    for i=1, #suspectedElements do
        local elem = suspectedElements[i]
        if elem:GetRowIndex() > maxIndex  then 
            maxIndex = elem:GetRowIndex() 
            maxElem = elem
        end 
    end
    
    return maxElem
end             

function IsPointInside(pX,pY,min,max)
    return 
    pX>=min.x
    and pX<=max.x  
    and pY>=min.y 
    and pY<=max.y
end

function L00_0200_puzzle01.CursorElementRelation(this,element,mX,mY)
    local min, max = element:GetBoundingRect()
    local minInside, maxInside = {x=min.x, y=min.y},{x=max.x, y=max.y}
    
    minInside.x=minInside.x+this.borderSize
    minInside.y=minInside.y+this.borderSize

    maxInside.x=maxInside.x-this.borderSize
    maxInside.y=maxInside.y-this.borderSize    
    
    local over = IsPointInside(mX,mY,min,max)
    local overCenter = IsPointInside(mX,mY,minInside,maxInside)
    return _else_(over and overCenter, "center", _else_(over and not overCenter , "border",nil) )
end

function L00_0200_puzzle01.CursorFromElement(this,element,mX,mY)
    local rel = this:CursorElementRelation(element,mX,mY)
    if rel == "center" then
        return "curs_rt"
    elseif rel == "border" then
        return  "curs_sw"
    else
        return "curs"
    end
end


function L00_0200_puzzle01.UpdateCursor(this,mX,mY)
    local element = this:ElementFromMousePos(mX,mY)
    if element then
        local cursor = this:CursorFromElement(element,mX,mY)
        SetElementCursor(element:GetName(),cursor)
    end
end


function L00_0200_puzzle01.SceneUpdate(this)                         
    
	local x, y = GetMousePos() 
    this:UpdateCursor(x, y)
	local x_, y_ = x, y

	--# bkg.elements.puzzle1_back:SetInteractive( this.draging==false )
	this.setBackButtonState(this.s_normal)
	--[[# if bkg.elements.puzzle1_back:IsPointInside(x, y) and  this.draging==false 
	then
		this.setBackButtonState(this.s_hover)
		if  IsMouseButtonDown(0)==true
		then
			this.setBackButtonState(this.s_pressed)
		end
	end ]]

	if x<L00_0200_puzzle01.leftMargin then x=L00_0200_puzzle01.leftMargin end
	if y<L00_0200_puzzle01.topMargin then y=L00_0200_puzzle01.topMargin end
	if x>OldInterfaceMap.width-L00_0200_puzzle01.rightMargin then x=OldInterfaceMap.width-L00_0200_puzzle01.rightMargin end
	if y>OldInterfaceMap.height-L00_0200_puzzle01.bottomMargin then y=OldInterfaceMap.height-L00_0200_puzzle01.bottomMargin end

	mousePos=this.vector(x,y,0)

    if IsMouseButtonDown(MB_LEFT)==true
	then

		if L00_0200_puzzle01.draging == true and this.dragSprite~=nil  -- L00_0200_puzzle01.draging sprite
		then
           
		    local newPos=this.dragStartSPos+mousePos-this.dragStartMPos

			this.dragSprite:e():SetPosition(newPos.x,newPos.y)
			this:SetSpriteGroupPosition(this.dragSprite)
            
            local dragingDistance=(this.dragStartMPos-mousePos):Length()
            if dragingDistance>10 then this.canII=false end
		end
	else

	    if this.draging==true and this.dragSprite~=nil then
            if this.dropPieceSound~="" then
                PlaySound(this.dropPieceSound)
            end
            this:MouseUp(this.dragSprite) 
        end
	    this.draging=false
		this.dragSprite=nil
		dragStartPosition=nil

	end

	if IsMouseButtonDown(MB_RIGHT)==true and wasRMouse==false	--R mouse down
	then
		wasRMouse=true
		
		this:RMouseDown();

	elseif IsMouseButtonDown(MB_RIGHT)==false then
		if wasRMouse==true then  
			--  RMouseUp :
	    end
        
		wasRMouse=false
		
	end
end
	
-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.SceneClean(this)
	this:Close_L00_0200()
	if this.old_SceneClean then this.old_SceneClean() end
end





--[[					save table structure 

	
	
	"zIndex1"=z
	"zIndex2"=z
	"zIndex3"=  ...
	
	"x1"=x1
	"y1"=y1
	"x2"=x2
	"y2"=y2 ...
	
	"frame1"=x
	"frame2"=y
	"frame3"=  ...

	"angle1"=x
	"angle2"=y
	"angle3"=  ...
	
	"gSize1"=size
	"g1"="name"
	"g2"="name"
	"g3"="name"...
	"gSize2"=size
	"g4"="name"
	"g5"="name"
	"g6"="name"...		

	this.sTable={}
	this.gTable={}
	this.charactersStates={}



]]

 --  s00_0100_map_minigame.L00_0200_puzzle01:Open_L00_0200()  
 --  s00_0100_map_minigame.L00_0200_puzzle01:Close_L00_0200()  
 --  s00_0100_map_minigame.L00_0200_puzzle01:Save()  
 --  s00_0100_map_minigame.L00_0200_puzzle01:Load() 

 --[[
 
 local top=bkg.elements["puzzle1_reg_top"]
  s00_0100_map_minigame.BringToFront("puzzle1_mk_puzzle1",top:GetRowIndex()-1)
 
 
  ]]
 
  --  s00_0100_map_minigame.L00_0200_puzzle01:Debug() 
 
L00_0200_puzzle01.Debug=
function(this)
	--[[print("debuf------------------------")
	for i=1,#bkg.elements
	do
		print(bkg.elements[i]:GetName())
	end
	
	print("ST:------------------------")
	for i=1,#this.sTable
	do
		print(this.sTable[i].s)
	end]]
	
	for i=1,#this.sTable
	do
		local size=#this.gTable[i]
	
		for j=1,size
		do

		end

	end
	
end
 


L00_0200_puzzle01.ElementFromName=
function(this,spriteName)

	for i=1,#this.sTable
	do
		if this.sTable[i].s==spriteName
		then
			return this.sTable[i]
		end
	end
	return nil
	
end



-----------------------------------------------------------SAVE-------------------------------------------------------------
L00_0200_puzzle01.Save=
function(this)

    local sTable = OldSavableTable(L00_0200_puzzle01.game_name)
	
	-- zOrder:
	local base=bkg.elements["puzzle1_reg_back"]:GetRowIndex()+1
	local top=bkg.elements["spr_puzzle1_top"]:GetRowIndex()-1
    
	for i=base,top do
		sTable["zIndex"..(i-base+1)]=bkg.elements[i]:GetName()
	end
	
	-- positions:
	for i=1,#this.sTable do
		local x,y=this.sTable[i]:e():GetPosition()
		sTable["x"..i] = x
		sTable["y"..i] = y
	end

	local nS=1
	local nE=1

	for i=1,#this.sTable do
		sTable["gSize"..nS]=#this.gTable[i]
	
		nS=nS+1
		
		for j=1,#this.gTable[i] do
			sTable["g"..nE]=this.gTable[i][j].s

			nE=nE+1
		end
	end
	
	for i=1,#this.sTable do
		sTable["INV"..i]=this.sTable[i].INV
	end	
	
	
	-- frames:
	for i=1,#this.sTable do
		sTable["frame"..i] = this:GetSpriteFrame(this.sTable[i].s)
	end
	
end


-----------------------------------------------------------LOAD-------------------------------------------------------------
 --  s00_0100_map_minigame.L00_0200_puzzle01:Open_L00_0200()  
 --  s00_0100_map_minigame.L00_0200_puzzle01:Close_L00_0200()  
 --  s00_0100_map_minigame.L00_0200_puzzle01:Save()  
 --  s00_0100_map_minigame.L00_0200_puzzle01:Load() 
 -- s00_0100_map_minigame.L00_0200_puzzle01.Init()

L00_0200_puzzle01.Load=
function(this)
  
	if SavableTableExists(L00_0200_puzzle01.game_name)==false  then
        return 
    end 
  
	local sTable = OldSavableTable(L00_0200_puzzle01.game_name)

	-- zOrder:
	for i=1,#this.sTable do
		local top=bkg.elements["spr_puzzle1_top"]

		BringToFront(sTable["zIndex"..i],top:GetRowIndex())
	end	
	-- positions:
	for i=1,#this.sTable do
		this.sTable[i]:e():SetPosition(sTable["x"..i],sTable["y"..i])
	end	
	
	local nS=1
	local nE=1
	this.gTable={}
	
	for i=1,#this.sTable do
		local size=sTable["gSize"..nS]

		nS=nS+1
		this.gTable[i]={}
		
		for j=1,size
		do
			table.insert(this.gTable[i],this:ElementFromName(sTable["g"..nE]))
			this:ElementFromName(sTable["g"..nE]).group=this.gTable[i]
			

			nE=nE+1
		end

	end
	
	-- frames:
	
	for i=1,#this.sTable do
        this.SetSpriteFrame(this.sTable[i].s,sTable["frame"..i])
	end	
	
	for i=1,#this.sTable do
		this.sTable[i].INV=sTable["INV"..i]
	end		

	
end


function L00_0200_puzzle01.SceneClean(this) 
end

function L00_0200_puzzle01.SceneSave(this) 
	this:Save()
end
	
-------------------------------------------------------------------------------------------
 --  s00_0100_map_minigame.L00_0200_puzzle01:Close_L00_0200()  
function L00_0200_puzzle01.Open_L00_0200(this , sceneElementsLoading)
	
	for i=1,L00_0200_puzzle01.sCount do
		local s=bkg.elements[L00_0200_puzzle01.prefix..i]
		s:Stop()
		local x,y=s:GetPosition()
		this.sTable[i]=L00_0200_puzzle01.CSprite(L00_0200_puzzle01.prefix..i,{},{},{},L00_0200_puzzle01.vector(x,y,0))
	end

    local savableExists = SavableTableExists(L00_0200_puzzle01.game_name.."rel")
    
    local sT = OldSavableTable(L00_0200_puzzle01.game_name.."rel")

	for i=1,L00_0200_puzzle01.sCount
	do	-- create start groups
		table.insert(L00_0200_puzzle01.gTable,{L00_0200_puzzle01.sTable[i]})
		this.sTable[i].group=L00_0200_puzzle01.gTable[#L00_0200_puzzle01.gTable]
		-- setting right (start) relations:

		for j=1,this.sCount
		do
			if i~=j
			then

				local x0,y0 = L00_0200_puzzle01.sTable[i]:e():GetPosition()
				local x1,y1 = L00_0200_puzzle01.sTable[j]:e():GetPosition()
                local name = L00_0200_puzzle01.prefix..""..j
                local name1 = name.."_"..i
                if not savableExists then
				    L00_0200_puzzle01.sTable[i].relations[name]=(L00_0200_puzzle01.vector(x1,y1,0)-L00_0200_puzzle01.vector(x0,y0,0))
                    sT[name1.."x0"] = x0
                    sT[name1.."y0"] = y0 
                    sT[name1.."x1"] = x1
                    sT[name1.."y1"] = y1
                else
                    L00_0200_puzzle01.sTable[i].relations[name]= L00_0200_puzzle01.vector(sT[name1.."x1"],sT[name1.."y1"],0) - L00_0200_puzzle01.vector(sT[name1.."x0"],sT[name1.."y0"],0)
                end
                
				local rel=(L00_0200_puzzle01.vector(x1,y1,0)-L00_0200_puzzle01.vector(x0,y0,0))
				rel.x=-rel.x
                
                
                if not savableExists then
                    L00_0200_puzzle01.sTable[i].relationsINV[name] = rel
                    sT[name1.."_i_x0"] = rel.x
                    sT[name1.."_i_y0"] = rel.y 
                else
                    L00_0200_puzzle01.sTable[i].relationsINV[name] = L00_0200_puzzle01.vector(sT[name1.."_i_x0"],sT[name1.."_i_y0"],0) 
                end   
				
			end
		end
	end

       
  
 -- L00_0200_puzzle01.sTable[i]:e():SetPosition(math.random(300,700),math.random(50,550))
    
    --  ramdomizin positions
 
	for i=1,L00_0200_puzzle01.sCount
	do
 
		L00_0200_puzzle01.sTable[i]:e():SetPosition(math.random(L00_0200_puzzle01.randomRangeMinX,L00_0200_puzzle01.randomRangeMaxX),math.random( L00_0200_puzzle01.randomRangeMinY,L00_0200_puzzle01.randomRangeMaxY))
        if L00_0200_puzzle01.twoSides then
            this.SetSpriteFrame(L00_0200_puzzle01.sTable[i].s,math.random(1,8))
        else
            this.SetSpriteFrame(L00_0200_puzzle01.sTable[i].s,math.random(1,4))
        end
		if this:GetSpriteFrame(L00_0200_puzzle01.sTable[i].s)>=5 then
			L00_0200_puzzle01.sTable[i].INV=true
		end
	end

    L00_0200_puzzle01:Load()

end                
	
-------------------------------------------------------------------------------------------

function L00_0200_puzzle01.Close_L00_0200(this) --  L00_0200_puzzle01:Open_L00_0200(this)  L00_0200_puzzle01:Close_L00_0200(this)  
	this:Save()
end

