
------------------------------------------------------------------------------
-- 
function CreateZoomZone(close_button_message, parentZoomZone, 
                        activeObject, activeObjectAngle,
                        navigationObject, navigationAngle,
						objects, invisibleObjects, attachedObjects)
	assert((parentZoomZone ~= nil and activeObject ~= nil and playField:HasObject(activeObject)) or
           (parentZoomZone == nil and activeObject == nil));

	-- (!) create zoom-zone list if it hasn't been created yet
	if gameState.zoomZones == nil then
		gameState.zoomZones = {};
	end

    local zone = {}
	assert(gameState.zoomZones[close_button_message] == nil);
	gameState.zoomZones[close_button_message] = zone;

	local biggestObject, buttonPosition = CalculateCloseButtonPosition(objects);
	local clippingRect = Rect();
    clippingRect.x1 = biggestObject:GetScrX() - biggestObject:GetAnimation():GetHotX();
    clippingRect.y1 = biggestObject:GetScrY() - biggestObject:GetAnimation():GetHotY(); 
    clippingRect.x2 = biggestObject:GetAnimation():GetWidth();
    clippingRect.y2 = biggestObject:GetAnimation():GetHeight();
    
	CreateZoomZoneFrame(biggestObject);

	if (parentZoomZone ~= nil) then --// if it's not a root zone
		if biggestObject:GetAnimation():GetWidth() == 640.0 then
		    zone.close_button = CreateCloseButton(buttonPosition, close_button_message, playField:GetLevelScreen());
		else
--			buttonPosition.x = buttonPosition.x - 70.0;
--			buttonPosition.y = buttonPosition.y + 40.0;
--		    zone.close_button = CreateBackButton(buttonPosition, close_button_message, playField:GetLevelScreen());
		end

        if (zone.close_button ~= nil) then
            zone.close_button:SetVisible(false);
            zone.close_button:Stop();
    	    zone.close_button:AttachTo(biggestObject);
    	    zone.close_button:SetZ(11.0);
        end    	    
	end

    zone.name = close_button_message;
    zone.biggestObject = biggestObject;
    zone.objects = {}
	zone.invisibleObjects = {}
	zone.colorTint = '0xFFFFFFFF';
	zone.bIsActive = true;
	zone.parentZoomZone = parentZoomZone;
	zone.activeObject = activeObject;
	zone.navigationObject = navigationObject;

    biggestObject:SetOpacity(0.0);
    
    for i,v in ipairs(objects) do
        if (playField:HasObject(v)) then
            local obj = playField:GetObject(v);

            if ( not IsActiveZoneObject(obj) ) then 
                obj:GetAnimation():SetColor(zone.colorTint);
            end

            obj:SetClippingRect(clippingRect.x1, clippingRect.y1, clippingRect.x2, clippingRect.y2);
            --// attach to biggest object of zoom-zone
            if (v ~= biggestObject:GetName()) then
                auxAttachInPlace(obj, biggestObject);
            end
            zone.objects[v] = true;
        else
           assert(false)
        end
    end
	for i,v in ipairs(invisibleObjects) do 
		assert(zone.objects[v] == true);

        local obj = playField:GetObject(v);
        obj:SetOpacity(0.0);
		zone.invisibleObjects[v] = true;
	end

	if (attachedObjects ~= nil) then
		for i,v in ipairs(attachedObjects) do 
			assert(playField:HasObject(v) == true);
            --// attach to biggest object of zoom-zone
            auxAttachInPlace(playField:GetObject(v), biggestObject);
		end
	end

    assert(gameState ~= nil and gameState.customCursors ~= nil);

    if (activeObject ~= nil) then
        assert(activeObjectAngle);
        if (gameState.customCursors[activeObject] == nil) then
            gameState.customCursors[activeObject] = {'CursorNavigation', activeObjectAngle};
        end
    end
    if (navigationObject ~= nil) then
        assert(navigationAngle);
        assert(gameState.customCursors[navigationObject] == nil and 'Specified object is already in use');
        gameState.customCursors[navigationObject] = {'CursorNavigation', navigationAngle};
    end

    AssignZoneMethods(zone);
    return zone
end

------------------------------------------------------------------------------
-- 
function BlockZone(zone)
	assert(gameState.lockedObjects ~= nil and gameState.customCursors ~= nil);
	gameState.lockedObjects[zone.activeObject] = true;
	gameState.customCursors[zone.activeObject] = nil;
	--// hide close button if zone is active and isn't root one
	if (zone.close_button ~= nil and gameState.activeZone == zone) then
        zone.close_button:SetVisible(false);
        zone.close_button:Stop();	
	end
end

------------------------------------------------------------------------------
-- 
function UnblockZone(zone, cursorType)
	assert(gameState.lockedObjects ~= nil and gameState.customCursors ~= nil);
	gameState.lockedObjects[zone.activeObject] = nil;
	gameState.customCursors[zone.activeObject] = {(cursorType == nil and 'CursorZoom' or cursorType)};
	--// show close button if zone is active and isn't root one
	if (zone.close_button ~= nil and gameState.activeZone == zone) then
        zone.close_button:SetVisible(true);
        zone.close_button:Go();	
	end
end

------------------------------------------------------------------------------
-- 
function CloseActiveZone(closeEvenIsRoot)
    closeEvenIsRoot = (closeEvenIsRoot == nil and false or true);

    assert(gameState ~= nil and gameState.activeZone ~= nil);
    if (closeEvenIsRoot == false) then
    	assert(gameState.activeZone.parentZoomZone ~= nil and 'Attept to close root zoom-zone');
    end

	OnButtonPress(gameState.activeZone.name);
end

------------------------------------------------------------------------------
-- 
function CloseAndBlockActiveZone()
    assert(gameState ~= nil and gameState.activeZone ~= nil);
	BlockZone(gameState.activeZone);
	CloseActiveZone();
end

------------------------------------------------------------------------------
-- 
function SetZoneVisible(zone, is_visible, switchTaskGroup)
	if (gameState.prevActiveZoneStack == nil) then
	    gameState.prevActiveZoneStack = {};
	end

    if (switchTaskGroup == nil) then
        switchTaskGroup = true;
    end

    zone.SetVisible(is_visible);
    if is_visible then
        gameState.locker:AddRef();

		local cnt = table.getn(gameState.prevActiveZoneStack);
		if gameState.activeZone ~= nil then
		    gameState.prevActiveZoneStack[cnt + 1] = gameState.activeZone;
			--// hide previous zom-zone if we open new big zoom-zone
if (zone.close_button == nil and gameState.activeZone.close_button == nil) then
	gameState.activeZone.SetVisible(false);
end
        end
        gameState.activeZone = zone;
    else
		gameState.locker:Release();

		local cnt = table.getn(gameState.prevActiveZoneStack);
		local prevZone = gameState.prevActiveZoneStack[cnt];

if (zone.close_button == nil and prevZone ~= nil and prevZone.close_button == nil) then
	prevZone.SetVisible(true);
end
        gameState.activeZone = prevZone;
        gameState.prevActiveZoneStack[cnt] = nil;
    end

    if (switchTaskGroup == true) then
        local panel = playField:GetLevelScreen():GetGamePanel();
        local taskGroupNameOnPanel = panel:GetCurrentTaskGroupName();
        local currentLocationName = auxGetZoomZoneName(GetLocationZone(gameState.activeZone));

        if (taskGroupNameOnPanel ~= currentLocationName) then
            panel:SwitchTaskGroup();
            local newTaskGroupOnPanel = panel:GetCurrentTaskGroupName();
--// (!)            assert(newTaskGroupOnPanel == currentLocationName);
			PlaySound('L99S15');
        end
    end
end


-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- 
function IsActiveZoneObject(gameObject)
-- (!) if current object is not an active zone object (has 01 alpha value)
    local color = gameObject:GetAnimation():GetColorStr();
	return string.sub(color, 1,4) == '0x01';
end

-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- 
function AssignZoneMethods(zone)
    zone.IsVisible = function()
	    assert(zone.biggestObject ~= nil and playField:HasObject(zone.biggestObject:GetName()) == true);

		local obj = zone.biggestObject;
		if obj:IsVisible() and obj:GetOpacity() > 0.0 then
			return true;
		end
        return false;
    end

    zone.SetVisible = function(is_visible)
        if (zone.close_button ~= nil) then
            zone.close_button:SetVisible(is_visible);

            if (is_visible and gameState.lockedObjects[zone.activeObject] == nil) then
                zone.close_button:Go();
            else
                zone.close_button:Stop();
            end
        end


        for i, v in pairs(zone.objects) do
            if zone.invisibleObjects[i] == nil and 
               v == true and playField:HasObject(i) then
                obj = playField:GetObject(i);

				if ( not IsActiveZoneObject(obj) ) then 
					obj:GetAnimation():SetColor(zone.colorTint);
				end
            end
        end

        assert(zone.biggestObject ~= nil and playField:HasObject(zone.biggestObject:GetName()) == true);
        local obj = zone.biggestObject;
        if is_visible then
		    obj:SetOpacity(0.01);
            obj:ChangeOpacity(0.01, 1., ZOOM_ZONE_APPEARING_TIME);
        else
		    obj:SetOpacity(1.0);
            obj:ChangeOpacity(1., 0., ZOOM_ZONE_APPEARING_TIME);
        end
    end

    zone.HasObject = function(object_name)
        return zone.objects[object_name] == true
    end

    zone.RemoveObject = function(object)
        zone.objects[object] = false
    end

    zone.AddObject = function(object)
        zone.objects[object] = true
    end

	zone.HideObject = function(objectName, duration)
		duration = (duration ~= nil and duration or 0.5);
		assert(zone.objects[objectName] == true);

		if (zone.invisibleObjects[objectName] ~= nil and obj:GetOpacity() == 0.0) then
		    return;
		end
		zone.invisibleObjects[objectName] = true;

        local obj = playField:GetObject(objectName)
        obj:ChangeOpacity(obj:GetOpacity(), 0.0, duration);
	end

	zone.UnhideObject = function(objectName, duration)
		duration = (duration ~= nil and duration or 0.5);
		assert(zone.objects[objectName] == true);

        local obj = playField:GetObject(objectName);

		if (zone.invisibleObjects[objectName] == nil and obj:GetOpacity() == 1.0) then
		    return;
		end
		zone.invisibleObjects[objectName] = nil;
		
        obj:ChangeOpacity(obj:GetOpacity(), 1.0, duration);
	end

	zone.SetColorTint = function(color)
		zone.colorTint = color;
	end

	zone.SetActive = function(bState)
		bIsActive = bState;
	end

	zone.IsActive = function()
		return bIsActive;
	end

	zone.GetActiveObject = function()
		return zone.activeObject;
	end

	zone.GetParentZone = function()
		return zone.parentZoomZone;
	end
end

-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- 
function CreateZoomZoneFrame(biggestObject)
    local biggestObjectWidth = biggestObject:GetAnimation():GetWidth();
    if biggestObjectWidth == 640.0 then
    	local frame = CreateSprite(); 
    	frame:AttachTo(biggestObject);
    	frame:SetSprite('ZoomZoneFrameTexture');
    	frame:SetXY(5.0, -10.0);

    	local frameTexRect = frame:GetTextureRect();
    	local objectHotSpotX = biggestObject:GetAnimation():GetHotX();
    	local objectHotSpotY = biggestObject:GetAnimation():GetHotY();
    	local frameHotSpotX = (frameTexRect.x2 - 640.0)/2.0 + objectHotSpotX;
    	local frameHotSpotY = (frameTexRect.y2 - 480.0)/2.0 + objectHotSpotY;

    	frame:SetHotSpot(frameHotSpotX, frameHotSpotY);	--// hot spot correction according to editor BUG! 8\
    	frame:SetZ(10.0);

		CreateWindowShade(frame, -20.0);
	end
end

-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- 
function CalculateCloseButtonPosition(zoneObjects)
    local bigestObject;
    for i,v in ipairs(zoneObjects) do
        if playField:HasObject(v) then
            local obj = playField:GetObject(v);
            if ( bigestObject == nil or 
                 obj:GetAnimation():GetWidth() > bigestObject:GetAnimation():GetWidth() ) then
                bigestObject = obj;
            end
        else
            assert(false);
        end
    end
    local buttonX = bigestObject:GetAnimation():GetWidth() - bigestObject:GetAnimation():GetHotX() - ZOOM_ZONE_CLOSE_BUTTON_SIZE.x / 2.0 + 25.0;
    local buttonY = -bigestObject:GetAnimation():GetHotY() + ZOOM_ZONE_CLOSE_BUTTON_SIZE.y / 2.0 + 8.0 - 25.0;
					--  (bigestObject:GetAnimation():GetHeight() - bigestObject:GetAnimation():GetHotY()) - ZOOM_ZONE_CLOSE_BUTTON_SIZE.y / 2.0;
    return bigestObject, Vector(buttonX, buttonY)
end
