private function getHeaders(NodePath $nodePath, &$parent = false)
    {
        $headers = [];
        $nodeData = $this->structure->getNode($nodePath);
        if ($nodeData['nodeType'] == 'scalar') {
            $headers[] = $nodeData['headerNames'];
        }
        if (is_array($parent) && !empty($parent)) {
            foreach ($parent as $key => $value) {
                // check all parent columns
                $previousPath = $nodePath->popLast();
                $previousNode = $this->structure->getNode($previousPath);
                /* this is a slight WTF, but getHeaders is called for every row, so the below code must
                     not be called if the parent was already generated. */
                $actualKey = $this->structure->encodeNodeName($key);
                if (!isset($previousNode[$key]) && !isset($nodeData[Structure::ARRAY_NAME][$actualKey]) &&
                    empty($nodeData[$actualKey]['type']) &&
                    empty($nodeData[Structure::ARRAY_NAME][$actualKey]['type'])
                ) {
                    // check that there is a column with a same name as a column with parent name
                    if (isset($previousNode[Structure::ARRAY_NAME][$actualKey])) {
                        // generate new column name
                        $newColName = $key;
                        $i = 0;
                        while (isset($previousNode[Structure::ARRAY_NAME]
                            [$this->structure->encodeNodeName($newColName)])
                        ) {
                            $newColName = $key . '_u' . $i;
                            $i++;
                        }
                        // rename the column in parent
                        $parent[$newColName] = $value;
                        unset($parent[$key]);
                        $this->structure->setParentTargetName($key, $newColName);
                        $key = $newColName;
                    }
                    // either way we need to store the parent column in structure
                    $previousNode[Structure::ARRAY_NAME][$this->structure->encodeNodeName($key)] =
                        ['nodeType' => 'scalar', 'type' => 'parent'];
                    $this->structure->saveNode($previousPath, $previousNode);
                    $this->structure->generateHeaderNames();
                    $nodeData = $this->structure->getNode($nodePath);
                }
            }
        }
        foreach ($nodeData as $nodeName => $data) {
            if (is_array($data) && ($data['nodeType'] == 'object')) {
                $pparent = false;
                $nodeName = $this->structure->decodeNodeName($nodeName);
                $ch = $this->getHeaders($nodePath->addChild($nodeName), $pparent);
                $headers = array_merge($headers, $ch);
            } else if (is_array($data)) {
                $headers[] = $data['headerNames'];
            }
        }
        return $headers;
    }