private static void ParsePagesRecursively(string path, SiteStructure site, XmlNodeList xmlPages, PortalPage parentPage)
        {
            foreach (XmlNode xmlPage in xmlPages)
            {
                PortalPage page = new PortalPage();
                page.ParentPage = parentPage;

                // page properties
                if (xmlPage.Attributes["name"] == null)
                {
                    throw new Exception(String.Format("Page name is not specified. File: {0}, Node: {1}",
                                                      path, xmlPage.OuterXml));
                }
                page.Name = xmlPage.Attributes["name"].Value;

                if (xmlPage.Attributes["roles"] == null)
                {
                    page.Roles.Add("*");
                }
                else
                {
                    page.Roles.AddRange(xmlPage.Attributes["roles"].Value.Split(ROLES_DELIMITERS.ToCharArray()));
                }

                if (xmlPage.Attributes["selectedUserContext"] != null)
                {
                    page.Roles.AddRange(xmlPage.Attributes["selectedUserContext"].Value.Split(ROLES_DELIMITERS.ToCharArray()));
                }

                page.Enabled      = (xmlPage.Attributes["enabled"] != null) ? Boolean.Parse(xmlPage.Attributes["enabled"].Value) : true;
                page.Hidden       = (xmlPage.Attributes["hidden"] != null) ? Boolean.Parse(xmlPage.Attributes["hidden"].Value) : false;
                page.Align        = (xmlPage.Attributes["align"] != null) ? xmlPage.Attributes["align"].Value : null;
                page.SkinSrc      = (xmlPage.Attributes["skin"] != null) ? xmlPage.Attributes["skin"].Value : null;
                page.AdminSkinSrc = (xmlPage.Attributes["adminskin"] != null) ? xmlPage.Attributes["adminskin"].Value : null;

                if (xmlPage.Attributes["url"] != null)
                {
                    page.Url = xmlPage.Attributes["url"].Value;
                }

                if (xmlPage.Attributes["target"] != null)
                {
                    page.Target = xmlPage.Attributes["target"].Value;
                }

                // content panes
                XmlNodeList xmlContentPanes = xmlPage.SelectNodes("Content");
                foreach (XmlNode xmlContentPane in xmlContentPanes)
                {
                    ContentPane pane = new ContentPane();
                    if (xmlContentPane.Attributes["id"] == null)
                    {
                        throw new Exception(String.Format("ContentPane ID is not specified. File: {0}, Node: {1}",
                                                          path, xmlContentPane.ParentNode.OuterXml));
                    }
                    pane.Id = xmlContentPane.Attributes["id"].Value;
                    page.ContentPanes.Add(pane.Id, pane);

                    // page modules
                    XmlNodeList xmlModules = xmlContentPane.SelectNodes("Module");
                    foreach (XmlNode xmlModule in xmlModules)
                    {
                        PageModule module = new PageModule();
                        module.ModuleId = site.Modules.Count + 1;
                        module.Page     = page;
                        site.Modules.Add(module.ModuleId, module);

                        if (xmlModule.Attributes["moduleDefinitionID"] == null)
                        {
                            throw new Exception(String.Format("ModuleDefinition ID is not specified. File: {0}, Node: {1}",
                                                              path, xmlModule.ParentNode.OuterXml));
                        }
                        module.ModuleDefinitionID = xmlModule.Attributes["moduleDefinitionID"].Value.ToLower(CultureInfo.InvariantCulture);

                        if (xmlModule.Attributes["title"] != null)
                        {
                            module.Title = xmlModule.Attributes["title"].Value;
                        }

                        if (xmlModule.Attributes["icon"] != null)
                        {
                            module.IconFile = xmlModule.Attributes["icon"].Value;
                        }

                        if (xmlModule.Attributes["container"] != null)
                        {
                            module.ContainerSrc = xmlModule.Attributes["container"].Value;
                        }

                        if (xmlModule.Attributes["admincontainer"] != null)
                        {
                            module.AdminContainerSrc = xmlModule.Attributes["admincontainer"].Value;
                        }

                        if (xmlModule.Attributes["viewRoles"] == null)
                        {
                            module.ViewRoles.Add("*");
                        }
                        else
                        {
                            module.ViewRoles.AddRange(xmlModule.Attributes["viewRoles"].Value.Split(ROLES_DELIMITERS.ToCharArray()));
                        }

                        if (xmlModule.Attributes["readOnlyRoles"] != null)
                        {
                            module.ReadOnlyRoles.AddRange(xmlModule.Attributes["readOnlyRoles"].Value.Split(ROLES_DELIMITERS.ToCharArray()));
                        }


                        if (xmlModule.Attributes["editRoles"] == null)
                        {
                            module.EditRoles.Add("*");
                        }
                        else
                        {
                            module.EditRoles.AddRange(xmlModule.Attributes["editRoles"].Value.Split(ROLES_DELIMITERS.ToCharArray()));
                        }

                        // settings
                        XmlNodeList xmlSettings = xmlModule.SelectNodes("Settings/Add");
                        foreach (XmlNode xmlSetting in xmlSettings)
                        {
                            module.Settings[xmlSetting.Attributes["name"].Value] = xmlSetting.Attributes["value"].Value;
                        }

                        XmlNode xmlModuleData = xmlModule.SelectSingleNode("ModuleData");
                        if (xmlModuleData != null)
                        {
                            // check reference
                            if (xmlModuleData.Attributes["ref"] != null)
                            {
                                // load referenced module data
                                xmlModuleData = xmlModule.OwnerDocument.SelectSingleNode(
                                    "Pages/ModulesData/ModuleData[@id='" + xmlModuleData.Attributes["ref"].Value + "']");
                            }
                            module.LoadXmlModuleData(xmlModuleData.OuterXml);
                        }

                        pane.Modules.Add(module);
                    }
                }

                // add page to te array
                if (parentPage != null)
                {
                    parentPage.Pages.Add(page);
                }

                site.Pages.Add(page);

                // process children
                XmlNodeList xmlChildPages = xmlPage.SelectNodes("Pages/Page");
                ParsePagesRecursively(path, site, xmlChildPages, page);
            }
        }