Image class for a simple image with multiple sprites
Наследование: UIBaseObject
        private void LoadExternalCoroutine(string name, UIImage image)
        {
            string url = "file://" + GameManager.Instance.mainGame.ExternalResourcePath + "/" + name + ".jpg";
            Debug.Log(name);
            WWW www = new WWW(url);

            if (string.IsNullOrEmpty(www.error))
            {
             				www.LoadImageIntoTexture(loaderTexture);

                Sprite sprite = Sprite.Create(loaderTexture,
                    new Rect(0, 0, loaderTexture.width, loaderTexture.height),
                    // new Rect(0, 0, www.texture.width, www.texture.height),  //->this eat up memory!!
                    new Vector2(0.5f, 0.5f), 100.0f);

                Sprite[] sprites = new Sprite[1];
                sprites[0] = sprite;
                image.SetSprites(sprites);
                image.Sprite = 0;

                DestroyImmediate(www.texture);

            }
            else
            {
                Debug.LogWarning(www.error);

                image.SetSprites(UIManager.LoadSprite(name));
                image.Sprite = 0;
            }

            www.Dispose();
            www = null;
        }
		}//LoadSprite()
		
		/// <summary>
		/// Adds a UI button.		
		/// </summary>
		/// <param name="obj">Parent game object.</param>
		/// <param name="fileName">Resource file name with path, relative to Rersources folder.</param>
		public UIObject Add(UIType type, GameObject obj, string fileName, Sprite spr = null)
		{
			Log.Info("Add: <color=yellow>"+obj.name+" - id:"+obj.GetComponent<GUIText>()+"</color> type:"+type);

			//// Log.GameTimes("_______________-_-_-_-_-_ <color=yellow>"+fileName+" _____ obj: "+obj+"</color>, type: "+type);


			if(images.ContainsKey(obj.GetInstanceID()))
			{
			 	//give warning, then return existing one (ignore new registration)
			 	Log.Debug("This button already registered, ignoring new registration. <color=cyan>" + obj.name+"</color> ");
			 	return images[obj.GetInstanceID()];
			}

			Sprite[] sprList = new Sprite[1];
			if(fileName.Length == 0)
			{

				if(spr == null)
				{
					Log.Debug("This button <color=yellow>"+obj.name+"</color> has no image.");
				}
				else
				{
					Log.Debug("Sprite >>>>>>>>>>>>>>>>> "+spr.name);
					sprList[0] = spr;
				}
			}
			else
			{
				sprList = LoadSprite(fileName);
			}



			UIObject image = null;
			switch(type)
			{
				case UIType.Image:
					Log.Debug("Add UIImage");
					image = new UIImage(obj, sprList);
					break;

				case UIType.Button:
					Log.Debug("Add UIButton");
					image = new UIButton(obj, sprList);
					break;

				case UIType.ToggleButton:
					Log.Debug("Add UIToggleButton");
					image = new UIToggleButton(obj, sprList);
					break;
					
				case UIType.Slider:
					Log.Debug("Add UISlider");
					image = new UISlider(obj, sprList);
					break;

				case UIType.Character:
					Log.Debug("Add UICharacter");
					image = new UICharacter(obj, sprList);
					break;

				case UIType.ChartPie:
					Log.Debug("Add UIChartPie");
					image = new UIChartPie(obj);
					break;

				case UIType.ChartLine:
					Log.Debug("Add UIChartLine");
					image = new UIChartLine(obj);
					break;

				case UIType.Checkbox:
					Log.Debug("Add Checkbox");
					image = new UICheckbox(obj, sprList);
					break;

				default:
					Log.Exception("Invalid UIType to add:" + type);
					break;
			}

			//TODO remove this
			images.Add(obj.GetInstanceID(), image);
			
			//
			//images.Add(""+lastId++, image);
			//Log.Info("Button added:"+obj.name+" image:"+image.Name);

			return image;

		}//Add()
		}//LoadResources()

		/// <summary>
		/// Load object resources from dictionary
		/// TODO make more generic helpers and way of parse similar stuff.
		/// ie. transform parameter should be one parser for all
		/// </summary>
		public Dictionary<string, UIObject> LoadResources(
			Dictionary<string,object> dict, 
		    GameObject                gameObject = null)
		{
			//parse list of objects
			if(dict.ContainsKey("objects"))
			{

				// Log.Debug("Number of objects:"+((List<object>)dict["objects"]).Count);

				Dictionary<string, UIObject> screenObjects = new Dictionary<string, UIObject>();
			
				foreach(Dictionary<string,object> obj
					in ((List<object>)dict["objects"]))
				{
					 
					//Log.Debug("objects:"+obj["id"].ToString()+" type:"+obj["type"].ToString());
	

					if(obj.ContainsKey("type") 
						&& obj.ContainsKey("id"))
					{
						//string objId = obj["id"].ToString();
						
						//get id and prefix it by parent name
						string objId = obj["id"].ToString();						
						if(gameObject!=null) objId = gameObject.name+"."+objId;

						
						string objType = obj["type"].ToString();						
						// Log.Debug("Create ui object:"+objId+":"+objType);

						
						//create objects based on types
						if(objType == "image")
						{
							
							// Log.Debug("Create Image:"+objId);
							//TODO add creation of an image gameObject here or there?
							UIImage image = new UIImage(obj);
							if(gameObject)
								image.GameObject.transform.parent = gameObject.transform;

							image.Name = objId;
							//images.Add(objId, image);
							images.Add(image.GameObject.GetInstanceID(), image);

							screenObjects.Add(obj["id"].ToString(),image);


						}
						else if(objType == "button")
						{
							
							Log.Debug("Create Button:<color=yellow>"+objId+"</color>");
							UIButton button = new UIButton(obj);
							if(gameObject)
							{
								button.GameObject.transform.parent = gameObject.transform;
								button.Name = objId;
							}


							//images.Add(objId, button);
							images.Add(button.GameObject.GetInstanceID(), button);
							screenObjects.Add(obj["id"].ToString(),button);

						}

						else if(objType == "togglebutton" )
						{
							Log.Debug("Create Toggle Button:<color=yellow>"+objId+"</color>");
							UIToggleButton button = new UIToggleButton(obj);
							if(gameObject)
							{
								button.GameObject.transform.parent = gameObject.transform;
								button.Name = objId;
							}

							//TODO FIX_TOGGLE this hack! move button init to Settings.cs to Enter()
							// for SoundButton:
							// 	bool mutedMusic = AUDIO.AudioManager.Instance.MuteMusic;
							// 	bool mutedSfx = AUDIO.AudioManager.Instance.MuteSfx;
							// 	if(((mutedMusic) && (objId == "Settings.btn_Sound")) ||		// sets Sound button
							// 	   ((mutedSfx) && (objId == "Settings.btn_SoundEffects")))	// sets SoundEffects button
							// 	{
							// 		//button.SoundState = UISoundButton.UISoundButtonState.SOUNDOFF;
							// 		//button.SaveState = "Off";
							// 		button.Active = false;
							// 	}

							//images.Add(objId, button);
							images.Add(button.GameObject.GetInstanceID(), button);
							screenObjects.Add(obj["id"].ToString(),button);

						}
						else if(objType == "text")
						{
							
							Log.Debug("Create TEXT:<color=yellow>"+objId+"</color>");
							
							GameObject txt = new GameObject();
							txt.SetActive(false);
							txt.name = objId;
							UIText uiText = txt.AddComponent<UIText>() as UIText;
							uiText.Parse(obj);

							if(gameObject)
								txt.transform.parent = gameObject.transform;


							//images.Add(objId, text);
							txt.SetActive(true);
							screenObjects.Add(obj["id"].ToString(),uiText);

						}
						else if(objType == "popup")
						{
							//set prefab default to id and reset if defined							
							string prefab = (obj.ContainsKey("prefab")) 
								? obj["prefab"].ToString() : obj["id"].ToString();
							
							GameObject popup = GetPopup(obj["id"].ToString(), prefab);
							popup.SetActive(true);

							if(obj.ContainsKey("position"))
							{
								
								string pos = obj["position"].ToString();
								float px = System.Convert.ToSingle(pos.Split(',')[0]);
								float py = System.Convert.ToSingle(pos.Split(',')[1]);
								
								Log.Debug("HUD "+objId+" Position:"+px+","+py);
								popup.transform.position = new Vector3(px, py, 0);
								//this.gameObject.name = dict["position"].ToString();
							}
							if(obj.ContainsKey("rotation"))
							{
								
								string rot = obj["rotation"].ToString();
								float rx = System.Convert.ToSingle(rot.Split(',')[0]);
								float ry = System.Convert.ToSingle(rot.Split(',')[1]);
								
								//Log.Debug("Rotation:"+rot+":"+rx+","+ry);
								popup.transform.localRotation = Quaternion.Euler(new Vector3(rx, ry, 0));
							}
							if(obj.ContainsKey("scale"))
							{
								
								string sc = obj["scale"].ToString();
								float sx = System.Convert.ToSingle(sc.Split(',')[0]);
								float sy = System.Convert.ToSingle(sc.Split(',')[1]);
								
								popup.transform.localScale = new Vector3(sx, sy, 0);
								Log.Debug("Scale:"+sx+","+sy);
							}
							if(dict.ContainsKey("layer"))
							{
								string layer = dict["layer"].ToString();
								popup.layer = LayerMask.NameToLayer(layer);
								ChangeLayers(popup, layer);
								
							}
						}
						else if(objType == "hud")
						{

							//set prefab default to id and reset if defined							
							string prefab = (obj.ContainsKey("prefab")) 
									? obj["prefab"].ToString() : obj["id"].ToString();
							
							//Log.Debug("Create HUD as:"+prefab);
							GameObject hud = GetHud(obj["id"].ToString(), prefab);
							hud.SetActive(true);

							//Log.Warning("dict"+dict["layer"].ToString());
							if(obj.ContainsKey("position"))
							{

								string pos = obj["position"].ToString();
								float px = System.Convert.ToSingle(pos.Split(',')[0]);
								float py = System.Convert.ToSingle(pos.Split(',')[1]);

								Log.Debug("HUD "+objId+" Position:"+px+","+py);
								hud.transform.position = new Vector3(px, py, 0);
								//this.gameObject.name = dict["position"].ToString();
							}
							if(obj.ContainsKey("rotation"))
							{

								string rot = obj["rotation"].ToString();
								float rx = System.Convert.ToSingle(rot.Split(',')[0]);
								float ry = System.Convert.ToSingle(rot.Split(',')[1]);

								//Log.Debug("Rotation:"+rot+":"+rx+","+ry);
								hud.transform.localRotation = Quaternion.Euler(new Vector3(rx, ry, 0));
							}
							if(obj.ContainsKey("scale"))
							{
								string[] sc = obj["scale"].ToString().Split(',');
								float sx = System.Convert.ToSingle(sc[0]);
								float sy = System.Convert.ToSingle(sc[1]);
								float sz = 0;
								if (sc.Length > 2)
								{
									sz = System.Convert.ToSingle(sc[2]);
								}

								hud.transform.localScale = new Vector3(sx, sy, sz);
								Log.Debug(string.Format("Scale: {0}, {1}, {2}", sx, sy, sz));
							}
							// if(obj.ContainsKey("order"))
							// {
							// 	int order = System.Convert.ToInt32(obj["order"].ToString());
							// 	SortingOrder = order;

							// }
							if(obj.ContainsKey("layer"))
							{
								string layer = obj["layer"].ToString();
								hud.layer = LayerMask.NameToLayer(layer);
								ChangeLayers(hud, layer);

							}

							
						}
						else if(objType == "model")
						{
							
							//set prefab default to id and reset if defined							
							string prefab = (obj.ContainsKey("prefab")) 
								? obj["prefab"].ToString() : obj["id"].ToString();
							
							//Log.Debug("Create HUD as:"+prefab);
							GameObject hud = GetModel(obj["id"].ToString(), prefab);
							hud.SetActive(true);
							
							//Log.Warning("dict"+dict["layer"].ToString());
							if(obj.ContainsKey("position"))
							{
								
								string pos = obj["position"].ToString();
								float px = System.Convert.ToSingle(pos.Split(',')[0]);
								float py = System.Convert.ToSingle(pos.Split(',')[1]);
								float pz = System.Convert.ToSingle(pos.Split(',')[2]);
								
								Log.Debug("Model "+objId+" Position:"+px+","+py+","+pz);
								hud.transform.position = new Vector3(px, py, pz);
								//this.gameObject.name = dict["position"].ToString();
							}
							if(obj.ContainsKey("rotation"))
							{
								
								string rot = obj["rotation"].ToString();
								float rx = System.Convert.ToSingle(rot.Split(',')[0]);
								float ry = System.Convert.ToSingle(rot.Split(',')[1]);
								
								//Log.Debug("Rotation:"+rot+":"+rx+","+ry);
								hud.transform.localRotation = Quaternion.Euler(new Vector3(rx, ry, 0));
							}
							if(obj.ContainsKey("scale"))
							{
								
								string sc = obj["scale"].ToString();
								float sx = System.Convert.ToSingle(sc.Split(',')[0]);
								float sy = System.Convert.ToSingle(sc.Split(',')[1]);
								
								hud.transform.localScale = new Vector3(sx, sy, 0);
								Log.Debug("Scale:"+sx+","+sy);
							}
							// if(obj.ContainsKey("order"))
							// {
							// 	int order = System.Convert.ToInt32(obj["order"].ToString());
							// 	SortingOrder = order;
							
							// }
							if(obj.ContainsKey("layer"))
							{
								string layer = obj["layer"].ToString();
								hud.layer = LayerMask.NameToLayer(layer);
								ChangeLayers(hud, layer);
								
							}
							
							
						}
						else if(objType == "character")
						{
							
							Log.Debug("Create Character:<color=yellow>"+objId+"</color>");
							UICharacter uiChar = new UICharacter(obj);
							if(gameObject)
							{
								uiChar.GameObject.transform.parent = gameObject.transform;
								uiChar.Name = objId;
							}

							//TODO we might want this later
							//NPCView npcview = uiChar.GameObject.AddComponent<NPCView>();
							//npcview.id = objId;
							//npcview.image = uiChar;

							//read bubble info if any
							//TODO move this somewhere else? Should a bubble exist outside of uichar?
							if(obj.ContainsKey("bubble"))
							{
								foreach(Dictionary<string,object> bobj
									in ((List<object>)obj["bubble"]))
								{
									//TODO parse text parameter. (as text section?) This part is parsed
									//by UIText already, so we should only pass it over.
									//size (of text area), font, fontSize, anchor, alignment, wrapsize
									if(bobj.ContainsKey("position"))
									{

										string pos = bobj["position"].ToString();
										float px = System.Convert.ToSingle(pos.Split(',')[0]);
										float py = System.Convert.ToSingle(pos.Split(',')[1]);
										uiChar.bubblePosition = new Vector3(px, py, 0);
										Log.Debug("HUD "+objId+" bubble.Position:"+px+","+py);
									}

									if(bobj.ContainsKey("scale"))
									{

										string sc = bobj["scale"].ToString();
										float  sx = System.Convert.ToSingle(sc.Split(',')[0]);
										float  sy = System.Convert.ToSingle(sc.Split(',')[1]);
										uiChar.bubbleScale = new Vector3(sx, sy, 1);
										//Log.Debug("---------- bubble.scale:"+sx+","+sy);
									}

									if(bobj.ContainsKey("tail"))
									{

										uiChar.bubbleTail = bobj["tail"].ToString();
										
									}

								}
							}
							


							images.Add(uiChar.GameObject.GetInstanceID(), uiChar);
							screenObjects.Add(obj["id"].ToString(),uiChar);

						}
						else if(objType == "skit")
						{
							UISkit uiSkit = new UISkit(obj);
							if(gameObject)
							{
								uiSkit.GameObject.transform.parent = gameObject.transform;
								uiSkit.Name = objId;
							}

							if(obj.ContainsKey("bubble"))
							{
								foreach(Dictionary<string,object> bobj in ((List<object>)obj["bubble"]))
								{
									//TODO parse text parameter. (as text section?) This part is parsed
									//by UIText already, so we should only pass it over.
									//size (of text area), font, fontSize, anchor, alignment, wrapsize
									if(bobj.ContainsKey("position"))
									{

										string pos = bobj["position"].ToString();
										float px = System.Convert.ToSingle(pos.Split(',')[0]);
										float py = System.Convert.ToSingle(pos.Split(',')[1]);
										uiSkit.bubblePosition = new Vector3(px, py, 0);
									}

									if(bobj.ContainsKey("scale"))
									{

										string sc = bobj["scale"].ToString();
										float sx = System.Convert.ToSingle(sc.Split(',')[0]);
										float sy = System.Convert.ToSingle(sc.Split(',')[1]);
										uiSkit.bubbleScale = new Vector3(sx, sy, 1);
									}

									if(bobj.ContainsKey("tail"))
									{
										uiSkit.bubbleTail = bobj["tail"].ToString();
									}
								}
							}

							images.Add(uiSkit.GameObject.GetInstanceID(), uiSkit);
							screenObjects.Add(obj["id"].ToString(), uiSkit);
						}
						else if(objType == "video")
						{
							//Log.Info(" ---------------------------- -- ");
							//create canvas
							GameObject canvas = GameObject.CreatePrimitive(PrimitiveType.Quad);					
							GameObject.Destroy(canvas.GetComponent("MeshCollider"));
							canvas.name = objId;
							if(gameObject)
								canvas.transform.parent = gameObject.transform;

							UIVideo video = new UIVideo(canvas, obj);

							images.Add(video.GameObject.GetInstanceID(), video);
							screenObjects.Add(obj["id"].ToString(),video);

						}
					}
					else
					{
						Log.Error("Object missing id and/or type definition");
					}
				}

				return screenObjects;

			}

			return null;
		}//LoadResources()
	    /// <summary>
	    /// Helper for processing blinking of an image.
	    /// It will toggle the visible flag based on the preset values
	    /// </summary>
	    public void BlinkToggle(UIImage image)
	    {
	    	//Log.Info("BlinkToggle:"+image.Name);

	    	//TODO use reference here!!

	    	//TODO show/hide, but could use sprites states as well
			//image.Visible = !image.Visible;
			if(image.Sprite == 0)
				image.Sprite = 1;
			else if(image.Sprite == 1)
				image.Sprite = 0;

	    	if(--image.blinkNumber > 0)
	    	{

		    	TimerCondition relTimeCondBlink = 
					new TimerCondition(TimerType.Relative, image.blinkSpeed, gpm.DialogGame.TimeSource);
				timeTrigger = 
					new ScriptTrigger<UIImage>(1, 1, relTimeCondBlink.Check, null, BlinkToggle, image);

				gpm.DialogGame.AddTrigger(timeTrigger);
			}
			
			if(image.blinkNumber == 0)
			{
				image.Sprite = 0;
				//image.Visible = true;
			}
	    }
	    }//IsLayerVisible()

	    /// <summary>
	    /// Blink an image by numberOfBlinks times.
	    /// The speed of blinks depends on the speedInMs parameter.
	    /// </summary>
	    public void BlinkImage(UIImage image, int numberOfblinks = 2, double speedInMs = 200)
	    {
			if(image.blinkNumber == 0)
			{
				image.blinkNumber = numberOfblinks*2;
				image.blinkSpeed = speedInMs/1000;
				BlinkToggle(image);
			}
			else image.blinkNumber = numberOfblinks*2;

	    }//BlinkImage()
 public void Load(string name, UIImage image)
 {
     LoadExternalCoroutine(name, image);
 }
        /// <summary>
        /// Ctor
        /// </summary>
        public UIProgressBar(GameObject obj, UIImage[] images, UIProgressBarFunction onUpdate)
        {
            this.obj = obj;
            this.images = images;
            this.onUpdate = onUpdate;

            this.render = obj.GetComponent<SpriteRenderer>();
            if(this.render == null)
                Debug.LogError("Button must have a SpriteRenderer! ProgressBar:"+obj.name);
        }
        /// <summary>
        /// ctor for creating it from dictionary (from file)
        /// </summary>
        public UISkit(Dictionary<string,object> dict)
            : base(dict)
        {
            this.type = UIType.Skit;

            this.npc = NpcModels.Instance.Get(dict["id"].ToString());
            Emotion = npc.emotion;

            if (dict.ContainsKey("background"))
            {
                Dictionary<string,object> bg = (Dictionary<string,object>)dict["background"];
                if (bg.ContainsKey("sprite"))
                {
                    GameObject gameObject = new GameObject();
                    gameObject.name = "background";
                    gameObject.transform.parent = this.gameObject.transform;
                    SpriteRenderer renderer = gameObject.AddComponent<SpriteRenderer>();

                    background = (UIImage)UIManager.Instance.Add(UIType.Image, gameObject, bg["sprite"].ToString());
                    gameObject.transform.localRotation = Quaternion.Euler(Vector3.zero);

                    if(bg.ContainsKey("position"))
                    {
                        string[] pos = bg["position"].ToString().Split(',');
                        float px = System.Convert.ToSingle(pos[0]);
                        float py = System.Convert.ToSingle(pos[1]);

                        gameObject.transform.localPosition = new Vector3(px, py, 0);
                    }

                    if (bg.ContainsKey("order"))
                    {
                        renderer.sortingOrder = System.Convert.ToInt32(bg["order"].ToString());
                    }
                }
            }

            bubblePosition = new Vector3(0, 0, 0);
            bubbleTail = "N";
            bubbleScale = new Vector3(25, 25, 25);
        }
        /// <summary>
        /// Set up base components
        /// </summary>
        void Awake()
        {
            //get all childs
            foreach (Transform child in transform)
               			{
               				if(child.gameObject.name == "check")
               					checkObj = child.gameObject;
               				else if( child.gameObject.name == "npc")
               				{
               					npcObj = child.gameObject;
               					image = new UIImage(npcObj, UIManager.LoadSprite(spriteFile));

               				}
               				else if( child.gameObject.name == "symbol_Joint")
               					jointObj = child.gameObject;
               			}

            Log.Assert(checkObj, "Missing check in "+gameObject.name);
            Log.Assert(npcObj, "Missing npc in "+gameObject.name);
            //Log.Assert(image, "Missing image in "+gameObject.name);
            Log.Assert(jointObj, "Missing joint in "+gameObject.name);

            Check = false;
            image.Sprite = 0;
        }
        // Use this for initialization
        void Awake()
        {
            //Log.Debug("Image Start in "+gameObject.name);

            UIManager uiManager = UIManager.Instance;
            image = (UIImage)uiManager.Add(UIType.Image, gameObject, resourcePath);

            //Log.Debug("image count="+image.Count);
        }
 /// <summary>
 /// Initializa the uiImage
 /// </summary>
 void Init()
 {
     image = (UIImage)UIManager.Instance.Add(
         UIType.Image, gameObject, resourcePath);
 }