File: System\Xml\Xsl\XsltOld\RootAction.cs
Project: ndp\fx\src\XmlUtils\System.Data.SqlXml.csproj (System.Data.SqlXml)
//------------------------------------------------------------------------------
// <copyright file="RootAction.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
 
namespace System.Xml.Xsl.XsltOld {
    using Res = System.Xml.Utils.Res;
    using System;
    using System.Diagnostics;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Xml;
    using System.Xml.XPath;
    using System.Xml.Xsl.Runtime;
    using MS.Internal.Xml.XPath;
    using System.Security;
 
    internal class Key {
        XmlQualifiedName name;
        int              matchKey;
        int              useKey;
        ArrayList        keyNodes;
 
        public Key(XmlQualifiedName name, int matchkey, int usekey) {
            this.name     = name;
            this.matchKey = matchkey;
            this.useKey   = usekey;
            this.keyNodes = null;
        }
 
        public XmlQualifiedName Name { get { return this.name;     } }
        public int MatchKey          { get { return this.matchKey; } }
        public int UseKey            { get { return this.useKey;   } }
 
        public void AddKey(XPathNavigator root, Hashtable table) {
            if (this.keyNodes == null) {
                this.keyNodes = new ArrayList();
            }
            this.keyNodes.Add(new DocumentKeyList(root, table));
        }
 
        public Hashtable GetKeys(XPathNavigator root) {
            if (this.keyNodes != null) {
                for(int i=0; i < keyNodes.Count; i++) {
                    if (((DocumentKeyList)keyNodes[i]).RootNav.IsSamePosition(root)) {
                        return ((DocumentKeyList)keyNodes[i]).KeyTable;
                    }
                }
            }
            return null;
        }
 
        public Key Clone() {
            return new Key(name, matchKey, useKey);
        }
    }
 
    internal struct DocumentKeyList {
        XPathNavigator rootNav;
        Hashtable   keyTable;
 
        public DocumentKeyList(XPathNavigator rootNav, Hashtable keyTable) {
            this.rootNav = rootNav;
            this.keyTable = keyTable;
        }
 
        public XPathNavigator RootNav  { get { return this.rootNav ; } }
        public Hashtable      KeyTable { get { return this.keyTable; } }
    }
    
    internal class RootAction : TemplateBaseAction {
        private  const int    QueryInitialized = 2;
        private  const int    RootProcessed    = 3;
        
        private  Hashtable  attributeSetTable  = new Hashtable();
        private  Hashtable  decimalFormatTable = new Hashtable();
        private  List<Key>  keyList;
        private  XsltOutput output;
        public   Stylesheet builtInSheet;
        public   PermissionSet   permissions;
 
        internal XsltOutput Output {
            get { 
                if (this.output == null) {
                    this.output = new XsltOutput();
                }
                return this.output; 
            }
        }
 
        /*
         * Compile
         */
        internal override void Compile(Compiler compiler) {
            CompileDocument(compiler, /*inInclude*/ false);
        }
 
        internal void InsertKey(XmlQualifiedName name, int MatchKey, int UseKey){
            if (this.keyList == null) {
                this.keyList = new List<Key>();
            }
            this.keyList.Add(new Key(name, MatchKey, UseKey));
        }
 
        internal AttributeSetAction GetAttributeSet(XmlQualifiedName name) {
            AttributeSetAction action = (AttributeSetAction) this.attributeSetTable[name];
            if(action == null) {
                throw XsltException.Create(Res.Xslt_NoAttributeSet, name.ToString());
            }
            return action;
        }
 
 
        public void PorcessAttributeSets(Stylesheet rootStylesheet) {
            MirgeAttributeSets(rootStylesheet);
 
            // As we mentioned we need to invert all lists.
            foreach (AttributeSetAction attSet in this.attributeSetTable.Values) {
                if (attSet.containedActions != null) {
                    attSet.containedActions.Reverse();
                }
            }
 
            //  ensures there are no cycles in the attribute-sets use dfs marking method
            CheckAttributeSets_RecurceInList(new Hashtable(), this.attributeSetTable.Keys);
        }
 
        private void MirgeAttributeSets(Stylesheet stylesheet) {
            // mirge stylesheet.AttributeSetTable to this.AttributeSetTable
 
            if (stylesheet.AttributeSetTable != null) {
                foreach (AttributeSetAction srcAttSet in stylesheet.AttributeSetTable.Values) {
                    ArrayList srcAttList = srcAttSet.containedActions;
                    AttributeSetAction dstAttSet = (AttributeSetAction) this.attributeSetTable[srcAttSet.Name];
                    if (dstAttSet == null) {
                        dstAttSet = new AttributeSetAction(); {
                            dstAttSet.name             = srcAttSet.Name;
                            dstAttSet.containedActions = new ArrayList();
                        }
                        this.attributeSetTable[srcAttSet.Name] = dstAttSet;
                    }
                    ArrayList dstAttList = dstAttSet.containedActions;
                    // We adding attributes in reverse order for purpuse. In the mirged list most importent attset shoud go last one
                    // so we'll need to invert dstAttList finaly. 
                    if (srcAttList != null) {
                        for(int src = srcAttList.Count - 1; 0 <= src; src --) {
                            // We can ignore duplicate attibutes here.
                            dstAttList.Add(srcAttList[src]);
                        }
                    }
                }
            }
 
            foreach (Stylesheet importedStylesheet in stylesheet.Imports) {
                MirgeAttributeSets(importedStylesheet);
            }
        }
 
        private void CheckAttributeSets_RecurceInList(Hashtable markTable, ICollection setQNames) {
            const string PROCESSING = "P";
            const string DONE       = "D";
 
            foreach (XmlQualifiedName qname in setQNames) {
                object mark = markTable[qname];
                if (mark == (object) PROCESSING) {
                    throw XsltException.Create(Res.Xslt_CircularAttributeSet, qname.ToString());
                } else if (mark == (object) DONE) {
                    continue; // optimization: we already investigated this attribute-set.
                } else {
                    Debug.Assert(mark == null);
 
                    markTable[qname] = (object) PROCESSING;
                    CheckAttributeSets_RecurceInContainer(markTable, GetAttributeSet(qname));
                    markTable[qname] = (object) DONE;
                }
            }
        }
 
        private void CheckAttributeSets_RecurceInContainer(Hashtable markTable, ContainerAction container) {
            if (container.containedActions == null) {
                return;
            }
            foreach(Action action in container.containedActions) {
                if(action is UseAttributeSetsAction) {
                    CheckAttributeSets_RecurceInList(markTable, ((UseAttributeSetsAction)action).UsedSets);
                } else if(action is ContainerAction) {
                    CheckAttributeSets_RecurceInContainer(markTable, (ContainerAction)action);
                }
            }
        }
        
        internal void AddDecimalFormat(XmlQualifiedName name, DecimalFormat formatinfo) { 
            DecimalFormat exist = (DecimalFormat) this.decimalFormatTable[name];
            if (exist != null) {
                NumberFormatInfo info    = exist.info;
                NumberFormatInfo newinfo = formatinfo.info;
                if (info.NumberDecimalSeparator   != newinfo.NumberDecimalSeparator   ||
                    info.NumberGroupSeparator     != newinfo.NumberGroupSeparator     ||
                    info.PositiveInfinitySymbol   != newinfo.PositiveInfinitySymbol   ||
                    info.NegativeSign             != newinfo.NegativeSign             ||
                    info.NaNSymbol                != newinfo.NaNSymbol                ||
                    info.PercentSymbol            != newinfo.PercentSymbol            ||
                    info.PerMilleSymbol           != newinfo.PerMilleSymbol           ||
                    exist.zeroDigit               != formatinfo.zeroDigit             ||
                    exist.digit                   != formatinfo.digit                 ||
                    exist.patternSeparator        != formatinfo.patternSeparator 
                ) {
                    throw XsltException.Create(Res.Xslt_DupDecimalFormat, name.ToString());
                }
            }
            this.decimalFormatTable[name] = formatinfo;
        }
 
        internal DecimalFormat GetDecimalFormat(XmlQualifiedName name) {
            return this.decimalFormatTable[name] as DecimalFormat;
        }
 
        internal List<Key> KeyList{
            get { return this.keyList; }
        }
 
       internal override void Execute(Processor processor, ActionFrame frame) {
            Debug.Assert(processor != null && frame != null);
 
            switch (frame.State) {
            case Initialized:
                frame.AllocateVariables(variableCount);
                XPathNavigator root = processor.Document.Clone();
                root.MoveToRoot();
                frame.InitNodeSet(new XPathSingletonIterator(root));
               
                if (this.containedActions != null && this.containedActions.Count > 0) {
                    processor.PushActionFrame(frame);
                }
                frame.State = QueryInitialized;
                break;
            case QueryInitialized:
                Debug.Assert(frame.State == QueryInitialized);
                frame.NextNode(processor);
                Debug.Assert(Processor.IsRoot(frame.Node));
                if (processor.Debugger != null) {
                    // this is like apply-templates, but we don't have it on stack. 
                    // Pop the stack, otherwise last instruction will be on it.
                    processor.PopDebuggerStack();
                }
                processor.PushTemplateLookup(frame.NodeSet, /*mode:*/null, /*importsOf:*/null);
 
                frame.State = RootProcessed;
                break;
 
            case RootProcessed:
                Debug.Assert(frame.State == RootProcessed);
                frame.Finished();
                break;
            default:
                Debug.Fail("Invalid RootAction execution state");
		        break;
            }
        }
    }
}