private void btnEdit_Click(object sender, RoutedEventArgs e)
        {
            ComboTreeNode node = (ComboTreeNode)trvActivities.SelectedItem;

            trvActivities.BeginInit();


            if (node != null)
            {
                node.Header = txtActivityName.Text;
            }

            TextRange range;

            range = new TextRange(rtbDescription.Document.ContentStart, rtbDescription.Document.ContentEnd);
            if (node.rtbDescriptionMStream != null)
            {
                node.rtbDescriptionMStream.Position = 0;

                range.Save(node.rtbDescriptionMStream, DataFormats.Rtf);
                node.rtbDescriptionMStream.Position = 0;
            }



            GetTreeChanged = true;
            isListSaved    = false;

            m_ActivitiesTreeView = trvActivities.Items.Cast <ComboTreeNode>();



            trvActivities.EndInit();
        }
        private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
            ComboTreeNode selected_node = (ComboTreeNode)trvActivities.SelectedItem;

            if (selected_node != null)
            {
                if (selected_node.Parent == null) // is a toplevel node
                {
                    int idx = trvActivities.Items.IndexOf(selected_node);

                    trvActivities.BeginInit();
                    trvActivities.Items.RemoveAt(idx);
                    trvActivities.EndInit();
                    m_ActivitiesTreeView = trvActivities.Items.Cast <ComboTreeNode>();
                    GetTreeChanged       = true;
                    isListSaved          = false;
                }
                else if (selected_node.Parent.GetType() == typeof(ComboTreeNode))
                {
                    ComboTreeNode Parent = (ComboTreeNode)selected_node.Parent;
                    int           idx    = Parent.Items.IndexOf(selected_node);

                    trvActivities.BeginInit();
                    Parent.Items.RemoveAt(idx);
                    trvActivities.EndInit();
                    m_ActivitiesTreeView = trvActivities.Items.Cast <ComboTreeNode>();
                    GetTreeChanged       = true;
                    isListSaved          = false;
                }
            }
        }
        private void BtnAdd_Click(object sender, RoutedEventArgs e)
        {
            Cursor = Cursors.Wait;


            ComboTreeNode selected_node = (ComboTreeNode)trvActivities.SelectedItem;

            List <ComboTreeNode> new_tree = Find_and_addNode(m_ActivitiesTreeView, selected_node);

            if (selected_node != null)
            {
                if (trvActivities.ItemsSource != null)
                {
                    trvActivities.BeginInit();

                    trvActivities.ItemsSource = new_tree;
                    trvActivities.Items.Refresh();

                    trvActivities.EndInit();
                    GetTreeChanged = true;
                    isListSaved    = false;


                    txtActivityName.Text = "";
                }
            }
            else
            {
                MessageBox.Show("Must select an item first.", "Select an item", MessageBoxButton.OK, MessageBoxImage.Warning);
            }



            Cursor = Cursors.Arrow;
        }
        private List <ComboTreeNode> Find_and_addNode(IEnumerable <ComboTreeNode> iNode, ComboTreeNode selected_node)
        {
            bool itemfound       = false;
            bool addToplevelItem = false;

            List <ComboTreeNode> new_tree = new List <ComboTreeNode>(iNode);
            ComboTreeNode        new_item;

            if (selected_node == null) // user want to create a new toplevel item
            {
                new_item        = new ComboTreeNode {
                };
                addToplevelItem = true;
            }
            else
            {
                new_item = new ComboTreeNode {
                    Header = "<new item>", Level = selected_node.Level + 1
                };
            }

            if (addToplevelItem)
            {
                new_tree.Add(new_item);
            }
            else
            {
                foreach (ComboTreeNode n in new_tree)
                {
                    if (itemfound)
                    {
                        break;
                    }
                    if (n == selected_node)
                    {
                        n.Items.Add(new_item);
                        itemfound = true;
                        break;
                    }

                    foreach (ComboTreeNode i in n.Items)
                    {
                        if (i == selected_node)
                        {
                            i.Items.Add(new_item);
                            itemfound = true;
                            break;
                        }
                    }
                }
            }


            return(new_tree);
        }
        private void trvActivities_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e)
        {
            var item = sender as TreeView;

            ComboTreeNode selitem = (ComboTreeNode)item.SelectedItem;


            if (selitem != null)
            {
                rtbDescription.IsEnabled  = true;
                txtActivityName.IsEnabled = true;

                btnAddItem.IsEnabled    = true;
                btnEditItem.IsEnabled   = true;
                btnDeleteItem.IsEnabled = true;

                //mnuAddItem.IsEnabled = true;
                //mnuEditItem.IsEnabled = true;
                //mnuDeleteItem.IsEnabled = true;


                if ((string)selitem.Header == "<new item>")
                {
                    TextRange rtbRange = new TextRange(rtbDescription.Document.ContentStart, rtbDescription.Document.ContentEnd);

                    rtbRange.Text = "<new description...>";

                    txtActivityName.Text = (string)selitem.Header;
                }
                else
                {
                    LoadRTBContent(ref selitem);
                    txtActivityName.Text = (string)selitem.Header;
                }
            }
            else
            {
                // no selection
                rtbDescription.IsEnabled  = false;;
                txtActivityName.IsEnabled = false;

                btnAddItem.IsEnabled    = false;
                btnEditItem.IsEnabled   = false;
                btnDeleteItem.IsEnabled = false;

                //mnuAddItem.IsEnabled = false;
                //mnuEditItem.IsEnabled = false;
                //mnuDeleteItem.IsEnabled = false;
            }
        }
        void LoadRTBContent(ref ComboTreeNode selected_node)
        {
            TextRange range;


            if (selected_node.rtbDescriptionMStream != null)
            {
                if (selected_node.rtbDescriptionMStream.ToArray().Any())
                {
                    range = new TextRange(rtbDescription.Document.ContentStart, rtbDescription.Document.ContentEnd);

                    range.Load(selected_node.rtbDescriptionMStream, DataFormats.Rtf);
                    selected_node.rtbDescriptionMStream.Position = 0;
                }
                else
                {
                    rtbDescription.Document.Blocks.Clear();
                }
            }
        }
        private void PrintRecursive(ComboTreeNode node, ref FileStream fs, string listname)
        {
            //Print goodies


            string node_header_string = (string)node.Header + "|" + listname;
            int    node_level         = node.Level;

            //node.Parent;

            if (node_header_string != "" || node.rtbDescriptionMStream.ToArray().Any())
            {
                byte[] data = FormatByteArray(node.rtbDescriptionMStream.GetBuffer(), node_header_string, node_level);
                fs.Write(data, 0, data.Length);
            }

            //loop through the tree of activities
            foreach (ComboTreeNode tn in node.Items)
            {
                PrintRecursive(tn, ref fs, listname);
            }
        }
        private List <ComboTreeNode> Load_ChurchActivities_From_File(string filePath, Stream fstream)
        {
            List <ComboTreeNode> tree_array = new List <ComboTreeNode>()
            {
            };


            try
            {
                if (File.Exists($"{filePath}"))
                {
                    // STX = byte 0x02
                    // ETX = byte 0x03
                    //message = [STX(1byte) + header_byte_array (n bytes) + escape_seq (2 bytes)+payload + ETX(1byte)]



                    byte[] read_buffer = new byte[1024];
                    byte[] tmp_buf     = new byte[1024];


                    byte[] ETX_seq = new byte[2] {
                        0x03, 0x30
                    };
                    byte[] STX_seq = new byte[2] {
                        0x02, 0x20
                    };

                    byte[] escape_seq = new byte[2] {
                        0x0A, 0xA0
                    };

                    int node_level_length = 1;

                    //byte[] tmp_array = new byte[STX_seq.Length + node_level_length + header_byte_array.Length + escape_seq.Length + payload.Length + ETX_seq.Length];

                    int STXidx = 0;
                    int ETXidx = 0;

                    int    offset_size = 0;
                    int    idx         = 0;
                    int    bytes_read  = 0;
                    string node_header;
                    int    node_level     = 0;
                    int    payload_length = 0;


                    ComboTreeNode node;
                    MemoryStream  payload_data;

                    while ((bytes_read = fstream.Read(read_buffer, offset_size, read_buffer.Length - offset_size)) > 0)
                    {
                        //loop over read buffer
                        for (idx = 0; idx <= read_buffer.Length - 1; idx++)
                        {
                            // read untill get a STX
                            if (read_buffer[idx] == 0x02 && read_buffer[idx + 1] == 0x20)
                            {
                                STXidx = idx; //STXidx is the beginning of the STX sequence index in the read buffer array
                            }
                            // read until you get an ETX symbol
                            if (read_buffer[idx] == 0x03 && read_buffer[idx + 1] == 0x30)
                            {
                                ETXidx = idx + 1; //ETXidx is the end of the ETX sequence index in the read buffer array and at the end of 1 message
                            }
                            // if an STX and ETX is found decode the the data and find the next message (STX ETX)
                            if (read_buffer[STXidx] == (byte)ArrayFormat.STX && read_buffer[ETXidx] == 0x30)
                            {
                                //we found the beginning of the payload
                                for (int i = STXidx; i <= ETXidx - 2; i++)
                                {
                                    if (read_buffer[i] == 0x0A && read_buffer[i + 1] == 0xA0)
                                    {
                                        int header_size = (i - 1) - (STXidx + 1 + node_level_length);

                                        node_level = Convert.ToInt16(read_buffer[STXidx + 2]);

                                        node_header = Encoding.UTF8.GetString(read_buffer, STXidx + 3 /*beggining offset of node header*/, header_size);



                                        string[] ary_nodeHeader = node_header.Split('|');
                                        string   activityName   = ary_nodeHeader[0];
                                        string   listname       = ary_nodeHeader[1];

                                        node = new ComboTreeNode {
                                            Header = activityName, Level = node_level, activityList = listname
                                        };

                                        if (read_buffer[i + 2] == (byte)ArrayFormat.ETX)
                                        {
                                            payload_length             = 0;
                                            payload_data               = new MemoryStream();
                                            node.rtbDescriptionMStream = payload_data;
                                        }
                                        else

                                        {
                                            payload_data = new MemoryStream();

                                            payload_length = (ETXidx - 2) - (i + 2);

                                            payload_data.Write(read_buffer, i + 2, payload_length);


                                            node.rtbDescriptionMStream = payload_data;
                                            //string data = Encoding.UTF8.GetString(payload_data.GetBuffer(),0,payload_length);
                                        }

                                        tree_array.Add(node);

                                        break;
                                    }
                                }



                                STXidx = ETXidx + 1;
                                ETXidx = 0;
                            }
                            else if (idx == read_buffer.Length - 1 && ETXidx == 0)   //we read until the end of the buffer but cannot find an end of message sequence ETX
                            {
                                // if this is the last byte in the buffer and we have not found an ETX symbol

                                //calc new size of offset into read_buffer where the new data will go
                                offset_size = (read_buffer.Length - 1) - STXidx;


                                Buffer.BlockCopy(read_buffer, STXidx, tmp_buf, 0, offset_size);

                                //clear the read_buffer
                                for (int i = 0; i <= read_buffer.Length - 1; i++)
                                {
                                    read_buffer[i] = 0;
                                }

                                //copy the bytes from tmp_buffer back to the read_buffer at the 0 index in read buffer
                                Buffer.BlockCopy(tmp_buf, 0, read_buffer, 0, offset_size);
                                //clear the tmp_buffer
                                for (int i = 0; i <= read_buffer.Length - 1; i++)
                                {
                                    tmp_buf[i] = 0;
                                }
                            }
                        }
                    } // while readbytes
                }

                //else // activities file does not exist
                //{
                //    Cursor = Cursors.Arrow;
                //    MessageBox.Show("No Activities file found or file is in the wrong format! '*.xml'");
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "XML read error", MessageBoxButton.OK, MessageBoxImage.Error);
            }



            return(tree_array);
        }
        // variable that hold tree of headers read from XML file
        // private List<ActivityHeader> m_lstHeadersFromXML = new List<ActivityHeader>() { };



        public void InitTree(List <ComboTreeNode> tree)
        {
            ComboTreeNode parent_ptr = null;
            ComboTreeNode root_ptr   = null;
            ComboTreeNode child_ptr  = null;

            List <ComboTreeNode> tmp_tree = new List <ComboTreeNode>()
            {
            };

            // tree is already initialized
            //if (trvActivities.DataContext == null)
            //{
            //    trvActivities.DataContext = tree;
            //}

            //return;



            for (int i = 0; i <= tree.Count - 1; i++)
            {
                if (tree[i].Level == 0)
                {
                    if (root_ptr != null)
                    {
                        tmp_tree.Add(root_ptr);
                    }
                    root_ptr = tree[i];
                }

                /* This node is a child of the root node pointed to by root_ptr */
                else if (tree[i].Level == root_ptr.Level + 1)
                {
                    if (tree[i].Parent == null)
                    {
                        root_ptr.Items.Add(tree[i]);
                    }


                    parent_ptr = tree[i];
                }
                /* This node is a child of a parent node pointed to by parent_ptr */
                else if (tree[i].Level == parent_ptr.Level + 1)
                {
                    if (tree[i].Parent == null)
                    {
                        parent_ptr.Items.Add(tree[i]);
                    }

                    child_ptr = tree[i];
                }

                /* This node is a child of a child node pointed to by child_ptr
                 * parent_ptr becomes the node
                 */
                else if (tree[i].Level == child_ptr.Level + 1)
                {
                    if (tree[i].Parent == null)
                    {
                        child_ptr.Items.Add(tree[i]);
                    }

                    parent_ptr = tree[i];
                }
            }

            if (!tmp_tree.Contains(root_ptr))
            {
                tmp_tree.Add(root_ptr);
            }

            trvActivities.ItemsSource = tmp_tree;

            m_ActivitiesTreeView = trvActivities.ItemsSource.Cast <ComboTreeNode>();
        }